您能否给我一个 16 位(或更多)十进制数,该十进制数仅在第 15 位正确转换为双精度浮点圆
Can you give to me a 16 digits (or more) decimal number that converted in double precision floating point round correctly only at 15th?
对于单精度,最小位数保证为 6。
即9999978e3
和9999979e3
都将"收敛"到9999978496
.因此,无论我将使用什么小数,6 位数字始终由单精度浮点数学保证(至少对于 IEEE 754
)。
我认为同样适用于双精度,但最小值应为 15。我找不到证明这一点的十进制数,就像上面使用单精度一样。
你能给我一个吗?或者你会如何检索它?
9007199254740992
和 9007199254740993
都是 16 位数字,当存储为双精度IEEE754时,两者都具有值9007199254740992
。
即9007199254740993
的第 16 位数字是一个笑话。
我选择这个例子的灵感是,9007199254740992
是 2 的 54 次方,紧随IEEE754双精度类型的有效位数之后,第一个十进制数字恰好是9
。因此,尽管只有 16 位数字,但上面的奇数都无法表示!
坚持IEEE754双精度,如果你想要一个 0 到 1 范围内的例子,那么从二元有理0.75
开始,添加一个 order 1e-16
的值。很快,你会偶然发现0.7500000000000005
和0.7500000000000006
,它们都是0.75000000000000055511151231257827021181583404541015625
我已经详细说明(感谢@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;
}
}
您能否给我一个 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 Failedn");
}
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的范围内。
根据 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;
}
- visual在c++中将十进制数转换为二进制数
- C++从二进制转换为十进制数
- 为什么有时我输入一个整数,程序将第一个输入的数字打印成十进制数?
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- 将分数转换为十进制数并对其进行排序
- 如何使用链表将负十进制数转换为二进制?
- 以C++格式将十六进制字符串转换为十进制数
- 将大十六进制数转换为十进制形式(以 10 为基数的形式)的算法
- 我通过迭代加法将二进制数转换为十进制并检查单个字符(请参阅代码)的方法有什么问题?
- 将字节数组转换为 C++ 中的十进制数
- 您能否给我一个 16 位(或更多)十进制数,该十进制数仅在第 15 位正确转换为双精度浮点圆
- 使用堆栈将十进制数转换为二进制数
- 将浮点数转换为字符串,并指定精度和十进制数字数?
- 如何将字符数转换为十进制并返回或转换ASCII'A'-'Z'/'a'-'
- 将十进制数转换为包装 BCD,反之亦然
- 转换字符串十进制数时的精度
- C++Cout将字符串转换为保留所有小数的十进制数
- 将十进制数转换为二进制时出现意外结果
- 一个从x数制到十进制的转换器
- 将二进制向量转换为十进制数组