对于单精度,最小数字保证 6 。
即。 9999978e3
和9999979e3
都会"收敛"到9999978496
。
因此无论我使用什么小数, 6 数字总是由单精度浮点数学保证(至少对于IEEE 754
)。
同样我认为适用于双精度,但最小值应 15 。我无法找到一个证明这一点的十进制数,就像上面那个使用单精度一样。
你能给我一个吗?或者你会如何找回它?答案 0 :(得分:4)
9007199254740992
和9007199254740993
都是16位数字,当存储为IEEE754双倍时,它们都具有值9007199254740992
。
即。 9007199254740993
的第16位是一个笑话。
我选择这个例子的灵感是9007199254740992
是2的第54个幂,就在IEEE754 double类型的有效位数中的位数之后,第一个十进制数字恰好是{{1 }}。因此,尽管只有16位数字,但这个上面的奇数都没有代表!
坚持IEEE754双精度,如果你想要一个0到1范围内的例子,那么从二元有理9
开始,并添加一个0.75
阶的值。很快,您会偶然发现1e-16
和0.7500000000000005
0.7500000000000006
答案 1 :(得分:1)
我已经详细说明了(感谢@Bathsheba提示)一种算法,从小数部分开始并按需要的数字递增(在我的情况下为16)将发现(对于下面的10000个十进制)小数将碰撞到相同的二进制双精度IEEE754表示。随意调整它:
#include <iostream>
int main() {
std::cout.precision(100);
long long int decimalPart = 7500000000000005;
double value, temp = 0.0;
// add 1e-16 increment
for(int i = 0; i < 10000; i++) {
value = decimalPart / 1e16;
// found
if(temp == value) {
std::cout << "decimal found: 0." << decimalPart << std::endl;
std::cout << "it collides with: 0." << decimalPart - 1 << std::endl;
std::cout << "both stored (binary) as " << value << std::endl << std::endl;
}
decimalPart += 1;
temp = value;
}
}
答案 2 :(得分:1)
你能给我一个16位数(或更多)的十进制数,只能在15日正确地进行双精度浮点数转换吗?
这些数字并不罕见,因此很容易尝试限制在感兴趣范围内的各种字符串。
在大范围的16位十进制文本值中,大约10%失败。所有失败都以'4'
或更高的前导数字开头 - 这并不奇怪。
// Although a C++ post, below is some C code
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void form_text_number(char *buf, int significant_digits, int min_expo, int max_expo) {
unsigned i = 0;
buf[i++] = (char) (rand() % 9 + '1');
buf[i++] = '.';
for (int sd = 1; sd < significant_digits; sd++) {
buf[i++] = (char) (rand() % 10 + '0');
}
sprintf(buf + i, "e%+03d", rand() % (max_expo - min_expo + 1) + min_expo);
}
bool round_trip_text_double_text(const char *s, int significant_digits) {
double d = atof(s);
char buf[significant_digits + 10];
sprintf(buf, "%.*e", significant_digits - 1, d);
if (strcmp(s, buf)) {
printf("Round trip failed \"%s\" %.*e \"%s\"\n", s, significant_digits - 1 + 3,d, buf);
return false;
}
return true;
}
测试代码
void test_sig(unsigned n, int significant_digits, int min_expo, int max_expo) {
printf("Sig digits %2d: ", significant_digits);
while (n-- > 0) {
char buf[100];
form_text_number(buf, significant_digits, min_expo, max_expo);
if (!round_trip_text_double_text(buf, significant_digits)) {
return;
}
}
printf("None Failed\n");
}
int main(void) {
test_sig(10000, 16, -300, 300);
test_sig(10000, 16, -1, -1);
test_sig(1000000, 15, -300, 300);
test_sig(1000000, 15, -1, -1);
return 0;
}
输出
Sig digits 16: Round trip failed "8.995597974696435e+110" 8.995597974696434373e+110 "8.995597974696434e+110"
Sig digits 16: Round trip failed "6.654469376627144e-01" 6.654469376627144550e-01 "6.654469376627145e-01"
Sig digits 15: None Failed
Sig digits 15: None Failed
注意:当double
打印到许多失败字符串的3个额外数字时,这3个数字的范围是445到555.
答案 3 :(得分:0)
根据IEEE 754,有效位数(或尾数)有52个显式位和一个隐式额外位。因此,53位的所有整数精确表示为double
。 54位或更多位的整数将丢失低位,因此如果这些位非零,它们将不会精确表示。因此,未正确表示为double
的最小整数为1ULL << 53 + 1
显示它的程序:
#include <iostream>
#include <cstdint>
int main(int, char**) {
std::uint64_t i = (1ULL << 53) + 1;
double x = i;
std::uint64_t j = x;
std::cout << x << " " << i << " " << j << std::endl;
return 0;
}