C++ 精度使用 long long 和 double
C++ Precision using long long with double
我正在试验 C++。我写了一个简单的函数,它使用非常大的数字来计算三角形的面积。
我将两个大数传递给函数,并从一个单独的函数 getValue() return 一个来自不同方程的单独值。我很好奇为什么当我把 1 放在括号外的线上时,像这样:
return (long long)(a - b / 2.0) + b + 1;
我得到值 9007200509008001
当我将 1 放在括号内时,就像这样:
return (long long)(a - b / 2.0 + 1) + b;
我得到 9007200509008000
第二个值比第一个小一个,即使计算结果应该相同。
#include <iostream>
double triangleArea(int b, int h)
{
long long bh = (long long)b * h;
return 0.5 * bh;
}
long long getValue()
{
int deltaY = 18014400;
int deltaX = 1000000000;
long b = deltaY + deltaX + 1600;
double a = triangleArea(deltaX, deltaY);
return (long long)(a - b / 2.0) + b + 1;
}
int main(int argc, char **argv)
{
std::cout << getValue() << std::endl;
}
我确信答案对某些人来说可能是显而易见的,但我无法理解。有人可以解释一下吗?
当您除以 2.0
时,您将隐式转换为 double。双精度限制为大约 15 位十进制数字。所以第 16 位 会发生什么是完美定义的,但可能不是你所期望的。
如果你需要准确性,请尝试使用long long
或unsigned long long
并小心控制你没有溢出。如果还不够,你将不得不使用多精度算法(例如GMP)。因为一旦你使用双浮点数,你就被限制在 53 个二进制数字的精度,或者大约 15-16 个十进制数字。
long long
通常比 double
具有更高的精度。例如,如果两者都是 64 位,则 long long
的精度为 64 位,但 double
的精度仅为 53 位(隐含 msb=1 的 52 位尾数)。
在您的情况下,这意味着 a - b / 2.0 + 1
与 a - b / 2.0
相同 double
常数,但 (long long)(a - b / 2.0) + b + 1
与 long long
不同常数为 (long long)(a - b / 2.0) + b
.
问题是在您的除法和变量 a
.
处隐式转换为 double
查看以下示例以进行清关:
#include <iostream>
double triangleArea(int b, int h)
{
long long bh = (long long)b * h;
return 0.5 * bh;
}
long long getValue()
{
int deltaY = 18014400;
int deltaX = 1000000000;
long b = deltaY + deltaX + 1600;
double a = triangleArea(deltaX, deltaY);
long long c = b / 2.0;
long long d1 = a - c;
long long d2 = ((long long)a) - c + 1;
long long e1 = d1 + b + 1;
long long e2 = d2 + b;
return e1;
}
int main(int argc, char **argv)
{
std::cout << getValue() << std::endl;
}
long long
的显式转换正在解决您的特殊问题。
注意变量的准确性并在它们之间进行转换。
我正在试验 C++。我写了一个简单的函数,它使用非常大的数字来计算三角形的面积。
我将两个大数传递给函数,并从一个单独的函数 getValue() return 一个来自不同方程的单独值。我很好奇为什么当我把 1 放在括号外的线上时,像这样:
return (long long)(a - b / 2.0) + b + 1;
我得到值 9007200509008001
当我将 1 放在括号内时,就像这样:
return (long long)(a - b / 2.0 + 1) + b;
我得到 9007200509008000
第二个值比第一个小一个,即使计算结果应该相同。
#include <iostream>
double triangleArea(int b, int h)
{
long long bh = (long long)b * h;
return 0.5 * bh;
}
long long getValue()
{
int deltaY = 18014400;
int deltaX = 1000000000;
long b = deltaY + deltaX + 1600;
double a = triangleArea(deltaX, deltaY);
return (long long)(a - b / 2.0) + b + 1;
}
int main(int argc, char **argv)
{
std::cout << getValue() << std::endl;
}
我确信答案对某些人来说可能是显而易见的,但我无法理解。有人可以解释一下吗?
当您除以 2.0
时,您将隐式转换为 double。双精度限制为大约 15 位十进制数字。所以第 16 位 会发生什么是完美定义的,但可能不是你所期望的。
如果你需要准确性,请尝试使用long long
或unsigned long long
并小心控制你没有溢出。如果还不够,你将不得不使用多精度算法(例如GMP)。因为一旦你使用双浮点数,你就被限制在 53 个二进制数字的精度,或者大约 15-16 个十进制数字。
long long
通常比 double
具有更高的精度。例如,如果两者都是 64 位,则 long long
的精度为 64 位,但 double
的精度仅为 53 位(隐含 msb=1 的 52 位尾数)。
在您的情况下,这意味着 a - b / 2.0 + 1
与 a - b / 2.0
相同 double
常数,但 (long long)(a - b / 2.0) + b + 1
与 long long
不同常数为 (long long)(a - b / 2.0) + b
.
问题是在您的除法和变量 a
.
查看以下示例以进行清关:
#include <iostream>
double triangleArea(int b, int h)
{
long long bh = (long long)b * h;
return 0.5 * bh;
}
long long getValue()
{
int deltaY = 18014400;
int deltaX = 1000000000;
long b = deltaY + deltaX + 1600;
double a = triangleArea(deltaX, deltaY);
long long c = b / 2.0;
long long d1 = a - c;
long long d2 = ((long long)a) - c + 1;
long long e1 = d1 + b + 1;
long long e2 = d2 + b;
return e1;
}
int main(int argc, char **argv)
{
std::cout << getValue() << std::endl;
}
long long
的显式转换正在解决您的特殊问题。
注意变量的准确性并在它们之间进行转换。