我试图将两个float
乘以如下:
float number1 = 321.12;
float number2 = 345.34;
float rexsult = number1 * number2;
我想看到的结果是110895.582,但是当我运行代码时它只给了我110896.大多数时候我遇到了这个问题。任何计算器都会给出包含所有小数的精确结果。我怎样才能获得这个结果?
编辑:这是C代码。我正在使用XCode iOS模拟器。
答案 0 :(得分:11)
有很多四舍五入。
float a = 321.12; // this number will be rounded
float b = 345.34; // this number will also be rounded
float r = a * b; // and this number will be rounded too
printf("%.15f\n", r);
在三次单独的舍入后,我得到110895.578125000000000。
如果您希望精确度超过6位小数,则 使用double
而不是float
。 (注意,我说“十进制数字值”,因为你没有得到十进制数字,你得到二进制数。)就目前而言,错误的1/2 ULP(一个完美的最坏情况舍入结果)约为0.004。
如果您想要精确舍入的十进制数,则必须使用专门的十进制库来执行此类任务。 double
对于科学家而言具有足够的精确度,但如果你使用金钱,一切都必须100%准确。没钱浮点数。
与整数不同,浮点数在您习惯于陷入陷阱之前需要一些实际的工作。请参阅“What Every Computer Scientist Should Know About Floating-Point Arithmetic”,这是该主题的经典介绍。
编辑:实际上,我不确定代码会轮次三次。它可能会绕五次次,因为a
和b
的常量可能首先舍入为双精度,然后在存储时再舍入为单精度。但我不太清楚这部分C的规则。
答案 1 :(得分:3)
你永远不会得到那样的确切结果。
首先,number1≠321.12,因为该值无法在base-2系统中准确表示。你需要无限数量的位。
同样适用于number2≠345.34。
因此,您首先要使用不准确的值。
然后产品将被舍入,因为乘法会使有效位数加倍,但如果乘以浮点数,则产品必须再次存储在float
中。
您可能希望为您的号码使用基于10的系统。或者,如果您的数字只有小数的2位十进制数,您可以使用整数(在这种情况下32位整数就足够了,但最终可能需要64位):
32112 * 34534 = 1108955808。
代表321.12 * 345.34 = 110895.5808。
答案 2 :(得分:1)
由于使用C,您可以使用“%。xf”轻松设置精度,其中x是所需的精度。
例如:
float n1 = 321.12;
float n2 = 345.34;
float result = n1 * n2;
printf("%.20f", result);
输出:
110895.57812500000000000000
但请注意,float
仅提供六位精度。为了更好地精确使用double
。
答案 3 :(得分:1)
Printf也进行了一些舍入。考虑http://codepad.org/LLweoeHp:
float t = 0.1f;
printf("result: %f\n", t);
--
result: 0.100000
嗯,看起来很好。为什么?因为printf默认了一些精度并将输出四舍五入。让我们拨打小数点后的50个位置:http://codepad.org/frUPOvcI
float t = 0.1f;
printf("result: %.50f\n", t);
--
result: 0.10000000149011611938476562500000000000000000000000
那是不同的,不是吗?在625之后,浮动耗尽了容纳更多数据的能力,这就是我们看到零的原因。 double可以容纳更多数字,但二进制中的0.1不是有限的。 Double必须放弃,最终:http://codepad.org/RAd7Yu2r
double t = 0.1;
printf("result: %.70f\n", t);
--
result: 0.1000000000000000055511151231257827021181583404541015625000000000000000
在您的示例中,单独使用321.12就足以造成麻烦:http://codepad.org/cgw3vUKn
float t = 321.12f;
printf("and the result is: %.50f\n", t);
result: 321.11999511718750000000000000000000000000000000000000
这就是为什么在将浮点值呈现给人类之前必须对其进行舍入。
计算器程序根本不使用浮点数或双精度数。它们实现十进制数格式。例如:
struct decimal
{
int mantissa; //meaningfull digits
int exponent; //number of decimal zeroes
};
Ofc需要重新发明所有操作:加法,减法,乘法和除法。或者只是寻找一个十进制库。