对于单精度,最小数字保证是6。
也就是说,9999978e3和9999979e3都将“收敛”到9999978496。因此,无论我使用什么小数点,6数字总是由单精度浮点数学保证的(至少对于IEEE 754来说是这样)。
我认为这也适用于双精度,但最小值应该是15。我找不到一个十进制数来证明这一点,因为上面用的是单精度。
你能给我一个吗?或者你怎么找回它?
发布于 2017-11-07 11:36:53
9007199254740992和9007199254740993都是16位数字,当作为IEEE754双值存储时,两者都具有9007199254740992值。
也就是说,9007199254740993的第16位是个笑话。
我选择这个例子的灵感是,9007199254740992是2的第54次方,仅次于IEEE754双类型的意义中的位数,而第一个十进制数字恰好是9。因此,上面的奇数没有一个是有代表性的,尽管只有16位数字!
坚持IEEE754的双重精度,如果您想要0到1的范围内的示例,那么从并进的rational 0.75开始,并添加order 1e-16的值。很快,您就会发现0.7500000000000005和0.7500000000000006,它们都是0.75000000000000055511151231257827021181583404541015625
发布于 2017-11-07 14:52:58
我已经详细阐述了一种算法(感谢@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;
}
}发布于 2017-11-07 17:09:59
你能给我一个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之间。
https://stackoverflow.com/questions/47156067
复制相似问题