在 c++ 中将双精度转换为整数损失 1
Convert double to int lose 1 in c++
可能的重复项:
为什么这种双倍到整数的转换不起作用?
在 c++ 中将双精度转换为 int lose 1
#include <iostream>
#include <cmath>
using namespace std;
void main() {
double num = 1234.34;
int numInt = num;
double numAfterPoint = num - numInt; // 0.34
int counter = 1;
double numFloatPower = numAfterPoint;
while (true) {
numFloatPower = numAfterPoint * pow(10.0, counter);
cout << numFloatPower << " > " << (int)numFloatPower << " ";
system("pause");
counter++;
}
}
当前结果:
3.4 > 3 Press any key to continue . . .
34 > 33 Press any key to continue . . .
340 > 339 Press any key to continue . . .
3400 > 3399 Press any key to continue . . .
结果应为:
3.4 > 3 Press any key to continue . . .
34 > 34 Press any key to continue . . .
340 > 340 Press any key to continue . . .
3400 > 3400 Press any key to continue . . .
等。。。
cast-to-int 操作(int)doubleValue
执行截断,这意味着如果数字在内部表示为 33.9999999999...,它将被截断为 33。
如果需要执行舍入(3.9 → 4、3.4 → 3(,请使用 round()
。
注意:
- 1234.34
- 实际上是 1234.33999999999991814547684044...因为它不能用有限数量的二进制数字精确地表示,所以在第 53 位它将被四舍五入 因此,您的 0.34
- 实际上是 0.33999999999991814547684044...,
- 您的 3.4 实际上是 3.3999999999991814547684044...,
- 你的 34 实际上是 33.999999999991814547684044...,
- 您的 340 实际上是 339.99999999991814547684044...,
- 等。
浮点运算使用2的有限幂和来表示任意数字。像3.4
这样的数字,不完全是2的幂之和,可以四舍五入。在这种情况下,它略微向下舍入,可以说3.39996…
。然后,当您相乘时,结果将是 33.9996…
,根据舍入到零的规则,该结果将向下舍入为 33
。
C++控制台 I/O 足够智能,可以四舍五入到最接近的偶数,即显示多少位十进制数字,但计算机的内部数学电路对此一无所知。它使用值的完全精度,在本例中包含错误。
试着cout << setprecision( 20 );
看到丑陋的真相。
问题是你的第一个假设是错误的:
double num = 1234.34;
int numInt = num;
double numAfterPoint = num - numInt; // 0.34
std::cout << std::setprecision(17) << numAfterPoint << "n";
3.3999999999991815
现在,如果您在主循环中设置精度,您将获得以下数字。
3.3999999999991815 > 3
33.999999999991815 > 33
339.99999999991815 > 339
3399.9999999991815 > 3399
麻烦的是流打印代码在打印之前对结果进行舍入,导致它打印3.4
而不是3.3999999999
。这是因为 3.4 不能用二进制浮点数精确表示。
为了帮助你理解发生了什么,让我给你一个非常简单的解释,使用固定的小数位数来解释类似的问题。(您遇到的问题是由于固定的二进制位置造成的,这更难理解,但问题是一样的。
你能做的最好的代表1/3
就是.333333
.但现在3 * 1/3 != 1
.
您可以将2/3
表示为 .666666
,然后2 * 1/3 = 1/3
,但随后2/3 + 1/3 != 1
。
你可以表示2/3
为 .666667
,然后表示 2/3 + 1/3 = 1
,但随后2/3 - 1/3 - 1/3 != 0
和 2 * 1/3 != 2/3
。
由于舍入和有限的精度,您不应期望浮点数学生成完全正确的结果。
正如 1/3 没有精确的十进制表示形式一样,.34 也没有精确的二进制表示形式。
由于十进制数通常不能完全以二进制表示,因此num
不是 1234.34,而是最接近该数字的double
值。那个可能略小于 1234.34(例如,1234.339999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999在这种情况下,当然numAfterPoint
也略小于 0.34,使得 100*numAfterPoints 明显小于 34 等。由于转换为 int 会删除小数部分,即使它非常接近 1,您也会得到 33 而不是 34。
另一方面,如果直接输出浮点值,则会将其舍入到特定的位数(您可以使用流操纵器进行控制(。因此,除非您告诉流输出非常多的数字,否则您看不到差异。尝试
std::cout << std::setprecision(20) << numAfterPoint << 'n';
看看真正存储了什么价值。
- 如何反转整数参数包
- enum是C++中的宏变量还是整数变量
- 努力将整数转换为链表。不知道我在这里做错了什么
- 整数不会重复超过随机数
- 在C++中手动调整数组大小
- 检查输入是否不是整数或数字
- C++使用整数的压缩数组初始化对象
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 如何只允许用户输入正整数
- 如何在c++中从文本文件中逐行读取整数
- C++:如何循环通过向量中的整数元素
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 序列化,没有库的整数,得到奇怪的结果
- 在一定长度后从数组中打印时缺少整数
- 如何检测 std::vector::emplace_back 上的隐式转换损失整数精度
- 禁止具有精度损失的整数转换
- ceil、floor 和 round 在转换为整数时会遇到精度损失问题吗?
- 在 c++ 中将双精度转换为整数损失 1