我正在试图弄清楚我可以使用多大的数字作为浮点数和double
。但它不存储我预期的方式,除了整数值。 double
应该保存8个字节的信息,足以容纳变量a,但它不能保持正确。它显示1234567890123456768
,其中最后2位数字不同。当我在浮点变量214783648
的最后一位数中存储b
或任何数字时,它会显示相同的值214783648
。这应该是极限。那是怎么回事?
double a;
float b;
int c;
a = 1234567890123456789;
b = 2147483648;
c = 2147483647;
printf("Bytes of double: %d\n", sizeof(double));
printf("Bytes of integer: %d\n", sizeof(int));
printf("Bytes of float: %d\n", sizeof(float));
printf("\n");
printf("You can count up to %.0f in 4 bytes\n", pow(2,32));
printf("You can count up to %.0f with + or - sign in 4 bytes\n", pow(2,31));
printf("You can count up to %.0f in 4 bytes\n", pow(2,64));
printf("You can count up to %.0f with + or - sign in in 8 bytes\n", pow(2,63));
printf("\n");
printf("double number: %.0f\n", a);
printf("floating point: %.0f\n", b);
printf("integer: %d\n", c);
return 0;
答案 0 :(得分:8)
对于FLT_MAX
和{{1},可以存储在浮点类型中的最大(有限)数的问题的答案是DBL_MAX
或float
分别。
但是,这并不意味着该类型可以精确地表示每个较小的数字或整数(事实上,甚至不是接近)。
首先,您需要了解浮点数的所有位都不是“相等”。浮点数具有指数(8位IEEE-754标准double
,float
中的11位)和尾数(23和double
中的52位和float
分别)。通过将尾数(其具有隐含的前导1位和二进制点)乘以2 指数(在对指数进行归一化之后;其二进制值不直接使用)来获得该数字。还有一个单独的符号位,因此以下内容也适用于负数。
当指数改变时,尾数的连续值之间的距离也改变,即,指数越大,浮点数的连续可表示值越大。因此,您可以精确地存储给定幅度的一个数字,但不能存储“下一个”数字。还应该记住,一些看似简单的分数不能用任意数量的二进制数字精确表示(例如,double
,十分之一,是二进制的无限重复序列,如1/10
,三分之一,是小数)。
当涉及到整数时,您可以精确地表示最多2个 mantissa_bits + 1 幅度的每个整数。因此,IEEE-754 1/3
可以表示最多2 24 和float
最多2 53 的所有整数(在这些中的后半部分)范围连续的浮点值恰好是一个整数,因为整个尾数仅用于整数部分)。可以表示单个较大的整数,但它们间隔不止一个整数,即,您可以表示某些整数大于2 mantissa_bits + 1 但是每个整数只能达到那个数量级。
例如:
double
输出:
float f = powf(2.0f, 24.0f);
float f1 = f + 1.0f, f2 = f1 + 2.0f;
double d = pow(2.0, 53.0);
double d1 = d + 1.0, d2 = d + 2.0;
(void) printf("2**24 float = %.0f, +1 = %.0f, +2 = %.0f\n", f, f1, f2);
(void) printf("2**53 double = %.0f, +1 = %.0f, +2 = %.0f\n", d, d1, d2);
正如您所看到的,将2**24 float = 16777216, +1 = 16777216, +2 = 16777218
2**53 double = 9007199254740992, +1 = 9007199254740992, +2 = 9007199254740994
添加到2 mantissa_bits + 1 没有任何区别,因为结果不可表示,但添加1
会产生正确答案(如它发生了,在这个数量上,可表示的数字是两个整数,因为乘数已加倍)。
TL; DR IEE-754 2
可以精确地表示最多2 24 和float
最多2 53 的所有整数,但是只有一些更大的整数(可表示值的间距取决于幅度)。
答案 1 :(得分:7)
sizeof(double)
为8
,为true,但double
也需要一些位来存储 exponent 部分。
假设使用IEEE-754,double
可以精确地表示最多2 53 的整数,小于1234567890123456789
。
答案 2 :(得分:2)
答案 3 :(得分:1)
sizeof
对象仅报告它占用的内存空间。它不显示有效的范围。很可能有一个unsigned int
例如2 ** 16(65536)可能的值占用32位内存。
对于floating point个对象,它更难。它们由(简化的)两个字段组成:整数尾数和指数(参见链接文章中的详细信息)。两者都有固定的宽度。
由于尾数只有一个有限的范围,所以尾随位被截断或舍入,并且如果需要,则更正指数。这是一个永远不应该使用浮点类型来存储货币等精确值的原因之一。
十进制(注意:计算机使用二进制表示),尾数为4位数:
1000 --> 1.000e3
12345678 --> 1.234e7
您的实现的参数在float.h
中定义,类似于limits.h
,它提供整数参数。
答案 4 :(得分:0)
您可以通过打印存储在' limits.h'中的限制来打印标准POD类型的实际限制。头文件(对于C ++,等效的是' std :: numeric_limits'标识符,如下所示: enter link description here)
由于硬件不能分别与浮动类型一起工作,实际上硬件不能代表浮动类型,硬件使用硬件的位长来表示浮动类型。由于您没有浮动类型的无限长度,因此您只能显示/呈现特定精度的双变量。大多数硬件用于浮动类型表示IEEE-754标准。
为了获得更高的精确度,您可以尝试长时间的双倍' (取决于硬件,这可能是两倍的精度),AVX,SSE寄存器,大数字库或你自己做。
答案 5 :(得分:-2)
在Linux上,#include <float.h>
在Windows上,[person, company, city].forEach(function(fn) {
fn.name();
});
有一个相当全面的定义列表