简体   繁体   English

你能给我一个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?

For single precision, min digits guarantee are 6 . 对于单精度,最小数字保证为6

ie both 9999978e3 and 9999979e3 will "converge" to 9999978496 . 9999978e39999979e3都将“收敛”到9999978496 So whatever decimal I'll use, 6 digits are always guarantee by the single precision floating point math (at least, for IEEE 754 ). 因此无论我使用什么小数,单精度浮点数学总是保证6位数(至少对于IEEE 754 )。

The same I think apply for double precision, but the min value should be 15 . 我认为同样适用于双精度,但最小值应为15 I can't find a decimal number that proof this, as for above that use single precision. 我找不到证明这一点的十进制数,就像上面那个使用单精度一样。

Can you give to me one? 你能给我一个吗? Or how would you retrieve it? 或者你会如何找回它?

Both 9007199254740992 and 9007199254740993 are 16 digit numbers, and both have the value 9007199254740992 when stored as an IEEE754 double. 90071992547409929007199254740993都是16位数字,当存储为IEEE754双9007199254740992时,它们都具有值9007199254740992

ie the 16th digit of 9007199254740993 is a joke. 9007199254740993第16位是一个笑话。

My inspiration behind picking this example is that 9007199254740992 is the 54th power of 2, just after the number of bits in the significand of an IEEE754 double type, and the first decimal digit happens to be a 9 . 我选择这个例子的灵感来自于9007199254740992是2的第54次方,就在IEEE754双重类型的有效位数中的位数之后,第一个十进制数字恰好是9 So none of the odd numbers above this are representable, despite having only 16 digits! 因此,尽管只有16位数字,但这个上面的奇数都没有代表!


Sticking to IEEE754 double precision, if you want an example in the range 0 to 1, then start with the dyadic rational 0.75 and add a value of the order 1e-16 . 坚持IEEE754双精度,如果你想要一个0到1范围内的例子,那么从二元有理0.75开始,并加上1e-16阶的值。 Quickly, you'll stumble on 0.7500000000000005 and 0.7500000000000006 , which are both 0.75000000000000055511151231257827021181583404541015625 很快,你会0.75000000000000050.7500000000000006 ,这些都是0.75000000000000055511151231257827021181583404541015625

I've elaborated (thanks to @Bathsheba tips) an algorithm that, starting from a decimal part and increment it by needed digit (16th in my case) will found (for the following 10000 decimal) decimals that will collide to the same binary double precision IEEE754 representation. 我已经详细说明了(感谢@Bathsheba提示)一种算法,从小数部分开始并按需要的数字递增(在我的情况下为16)将发现(对于下面的10000个十进制)小数将碰撞到相同的二进制双精度精度IEEE754表示。 Feel free to adjust it: 随意调整它:

#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;        
    }
}

Can you give to me a 16 digits (or more) decimal number that converted in double precision floating point round correctly only at 15th? 你能给我一个16位数(或更多)的十进制数,它只能在15日正确转换为双精度浮点数吗?

Such numbers are not rare so easy enough to try various strings limited to the range of interest. 这样的数字并不罕见,因此很容易尝试限制在感兴趣范围内的各种字符串。

Over a wide range of 16 digit decimal text values, about 10% failed. 在大量16位十进制文本值中,大约10%失败。 All failures began with a leading digit of '4' or more - not surprising. 所有失败都以'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;
}

Test code 测试代码

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;
}

Output 产量

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

Note: When the double was printed to 3 extra digits for many failed strings, those 3 digits were in the range 445 to 555. 注意:当double打印到许多失败字符串的3个额外数字时,这3个数字在445到555范围内。

There are 52 explicit bits for significand (or mantissa) and one implicit extra bit according to IEEE 754. So all integers of 53 bits are represented precisely as double . 根据IEEE 754,有效位数(或尾数)有52个显式位和一个隐式额外位。因此,53位的所有整数精确表示为double Integers of 54 or more bits will lose low bits, so they will not represented precisely if that bits are non-zero. 54位或更多位的整数将丢失低位,因此如果这些位非零,它们将不会精确表示。 So least integer that not represented precisely as double is 1ULL << 53 + 1 因此,未精确表示为double最小整数是1ULL << 53 + 1

Program that shows it: 显示它的程序:

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM