double的十进制表示中的连续零的数量

  发布于 2023-02-13 22:17
  • php
  • IEEE 754双精度数的精确十进制表示中连续非前导非尾随零(相应的nines)的最大数量是多少?

    上下文

    考虑将a转换double为十进制,向上舍入(分别向下)的问题,当你能够使用的唯一原语是转换为最近的(正确舍入到任意所需数字的数字)的现有函数时.

    您可以获得一些额外的数字并自行删除它们.例如,要1.875在点后向下舍入到一位数,可以将其转换为点(1.871.875)后面两位或三位数的最接近的十进制表示,然后自己擦除数字以获得预期的答案,1.8.

    对于某些数字和要打印的其他位数的选择,此方法会产生错误的结果.例如,对于double最近的0.799999996,转换为十进制,在点生成后舍入到最近的,2,3或4位0.80,0.8000.8000.0.8当所需结果为时,在转换后删除附加数字会产生结果0.7.

    在有限数量的情况下double,存在许多额外的数字,它们足以在初始转换中打印,以便在截断所获得的十进制表示之后始终计算正确的结果.此数字与a的精确十进制表示中可能出现的最大九或零数相关double.

    有关

    这个问题是有关这个问题有关的转换四舍五入double至小数点,而且是双重的关于正确舍入的转换十进制表示的双打这个问题.

    1 个回答
    • [简短版本:答案是20.重新解决问题,找到对形式数字的良好理性近似2^e / 10^d; 然后使用续流分查找每个合适的最好这样近似de.]

      答案似乎是20:即,有一些IEEE 754 binary64浮点数的例子,其十进制扩展具有20连续的零,但21在它们的十进制扩展中没有连续的零(不包括前导零和尾随零).对于九个字符串也是如此.

      对于第一部分,我需要做的就是展示这样的浮动.该值0x1.9527560bfbed8p-1000可以完全表示为binary64 float,其十进制扩展包含20个零的字符串:

      1.-301

      对于关于9的问题的部分,十进制扩展0x1.c23142c9da581p-405包含20个9的字符串:

      2.12818792307269553358078502102171540639252016258831784842556110831434197718043638405555406495645619729155240037555858106390933161420388023706431461384056688295540725831155392678607931808851292893574214797681879999999999999999999941026584542575391157788777223962620780080784703190447744595561259568772261019375946489162743091583251953125E-122

      为了解释我如何找到上面的数字,并表明没有21个连续零的例子,我们需要更努力地工作.与787-9或0,在其十进制扩展长长的一串实数的形式(a + eps)*10^d对一些整数ad和实数eps,具有a非零(我们不妨假设a正)和eps非零和小.例如,如果0 < abs(eps) < 10^-10然后a + eps具有至少10个零的小数点以下的(如果eps是正的),或跟随在小数点10九(如果eps是负的); 乘以10^d允许移动零或九的串的位置.

      但我们对上述形式的数字感兴趣,它们同时可以表示为IEEE 754 binary64 float; 换句话说,这也是形式的数字b*2^e为整数be满足2^52 <= b <= 2^53,用e有限的范围内(并与一些额外的限制,b一旦我们进入低于正常范围,但是我们可以不用担心以后).

      所以结合这一点,我们正在寻找解决方案,(a + eps) * 10^d = b * 2^e在整数a,b,de这样eps小,a是积极的,2^52 <= b <= 2^53(我们会担心的范围de更高版本).重新排列,我们得到eps / b = 2^e / 10^d - a / b.换句话说,我们正在寻找2^e / 10^d具有有限分母的良好理性近似.这是连续分数的经典应用:给定,d并且e,可以有效地找到具有分母的分母的最佳有理逼近2^53.

      所以解决方案策略一般是:

      for each appropriate d and e:
          find the best rational approximation a / b to 2^e / 10^d with denominator <= 2^53
          if (the error in this rational approximation is small enough):
              # we've got a candidate
              examine the decimal expansion of b*2^e
      

      对于e来说,我们只有大约2千个值来检查,最坏的是每个这样的e几百d,所以整个过程在计算上非常可行.

      现在详细说明:"足够小"是什么意思?哪个de"适当"?

      至于"足够小":让我们说我们正在寻找至少19个零或9的字符串,所以我们正在寻找解决方案0 < abs(eps) <= 10^-19.所以,它足以发现,对于每一个de所有ab这样abs(2^e / 10^d - a / b) <= 10^-19 * 2^-52.请注意,由于限制,b只能有一个这样的分数a / b; 如果还有另一个这样的a' / b'话我们就有1 / 2^106 <= 1 / (b *b') <= abs(a / b - a' / b') <= 2 * 10^-19 * 2^-52了矛盾.因此,如果存在这样的分数,则必然是给定分母界限的最佳有理逼近.

      对于de:要覆盖包括次正规的binary64范围,我们希望e范围从包含-1126971包含.如果d太大,那么2^e / 10^d将会小得多,2^-53并且没有解决方案的希望; d <= 16 + floor(e*log10(2))是一个实际的约束.如果d太小(或太负)那么2^e / 10^d将是一个整数并且没有解决方案; 为了避免这种情况,我们想要d > min(e, 0).

      有了所有内容,让我们编写一些代码.Python解决方案非常简单,部分原因在于Fraction.limit_deminator方法的存在,它完全可以在极限范围内找到最佳有理逼近.

      from fractions import Fraction
      from itertools import groupby
      from math import floor, log10
      
      def longest_run(s, c):
          """Length of the longest run of a given character c in the string s."""
          runs = [list(g) for v, g in groupby(s, lambda k: k == c) if v]
          return max(len(run) for run in runs) if runs else 0
      
      def closest_fraction(d, e):
          """Closest rational to 2**e/10**d with denominator at most 2**53."""
          f = Fraction(2**max(e-d, 0) * 5**max(-d, 0), 2**max(0, d-e) * 5**max(0, d))
          approx = f.limit_denominator(2**53)
          return approx.numerator, approx.denominator
      
      seen = set()
      emin = -1126
      emax = 971
      for e in range(emin, emax+1):
          dmin = min(e, 0) + 1
          dmax = int(floor(e*log10(2))) + 16
          for d in range(dmin, dmax+1):
              num, den = closest_fraction(d, e)
              x = float.fromhex('0x{:x}p{}'.format(den, e))
              # Avoid duplicates.
              if x in seen:
                  continue
              seen.add(x)
              digits = '{:.1000e}'.format(x).split('e')[0].replace('.','').strip('0')
              zero_run = longest_run(digits, '0')
              if zero_run >= 20:
                  print "{} has {} zeros in its expansion".format(x.hex(), zero_run)
              nine_run = longest_run(digits, '9')
              if nine_run >= 20:
                  print "{} has {} nines in its expansion".format(x.hex(), nine_run)
      

      那里有足够的性能改进空间(使用Python的fractions模块将是一个良好的开端:-); 就目前而言,需要几分钟才能完成.以下是结果:

      0x1.9527560bfbed8p-1000 has 20 zeros in its expansion
      0x1.fa712b8efae8ep-997 has 20 zeros in its expansion
      0x1.515476ae79b24p-931 has 20 nines in its expansion
      0x1.a5a9945a181edp-928 has 20 nines in its expansion
      0x1.86049d3311305p-909 has 20 zeros in its expansion
      0x1.69c08f3dd8742p-883 has 20 zeros in its expansion
      0x1.1b41d80091820p-861 has 20 zeros in its expansion
      0x1.62124e00b5e28p-858 has 20 zeros in its expansion
      0x1.ba96e180e35b2p-855 has 20 zeros in its expansion
      0x1.31c5be6377c48p-786 has 20 zeros in its expansion
      0x1.7e372dfc55b5ap-783 has 20 zeros in its expansion
      0x1.7e89dc1c3860ap-555 has 20 nines in its expansion
      0x1.7e89dc1c3860ap-554 has 20 nines in its expansion
      0x1.7e89dc1c3860ap-553 has 20 nines in its expansion
      0x1.7e89dc1c3860ap-552 has 20 nines in its expansion
      0x1.30bd91ea994cbp-548 has 20 zeros in its expansion
      0x1.4a5f9de9ee064p-468 has 20 nines in its expansion
      0x1.9cf785646987dp-465 has 20 nines in its expansion
      0x1.c23142c9da581p-408 has 20 nines in its expansion
      0x1.c23142c9da581p-407 has 20 nines in its expansion
      0x1.c23142c9da581p-406 has 20 nines in its expansion
      0x1.c23142c9da581p-405 has 20 nines in its expansion
      0x1.ba431f4e34be9p+738 has 20 nines in its expansion
      

      2023-02-13 22:41 回答
    撰写答案
    今天,你开发时遇到什么问题呢?
    立即提问
    热门标签
    PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有