当前位置: 首页 > 知识库问答 >
问题:

哪些单精度浮点数需要9位有效小数才能进行明确的十进制表示?

怀飞扬
2023-03-14

我在这篇维基百科文章中找到了以下关于单精度浮点数的陈述https://en.wikipedia.org/wiki/Single-precision_floating-point_format:

如果将IEEE 754单精度数字转换为具有至少9位有效数字的十进制字符串,然后转换回单精度表示,则最终结果必须与原始数字匹配。

我曾试图找到实际需要9位有效十进制数字的单精度浮点数示例,这些数字只有8位有效数字,并且还没有明确的含义,例如,通过在gdb调试器中打印浮点值,或者尝试将不同的值转换为倍频程中的单精度,但尚未发现需要8位以上十进制数字才能与直接相邻浮点值具有不同十进制表示形式的示例。

问题是,实际上是否存在需要9位十进制数字的单精度(32位)浮点值,或者这只是一个永远不需要的安全上限。您能否举一个单精度浮点值的例子,当转换为仅8位有效十进制数字然后转换回二进制浮点表示时,它的值与原始浮点值不同。

共有2个答案

司徒钱青
2023-03-14

是否确实存在需要9位小数(?)的单精度(32位)浮点值:操作

我试图找到实际需要9位有效十进制数字的单精度浮点数的示例,这些数字只有8位有效数字,并且没有明确的含义,并且没有找到任何:OP

鸽子洞原理

示例:在8到16之间,由于公共浮点的二进制编码,有2个不同的浮点线性分布。其中1/8在[10和11]之间:220或1048576个不同的值。前2个十进制数字是10。在10.xxx xxx中只多使用6个十进制数字只会产生1000000个不同的组合,但我们需要1048576。48576个浮点值与其他48576个相冲突。需要另一个十进制数字。更多详细信息

C规范使用以下以2为基数的浮点数来查找XXX\u DECIMAL\u DIG,这是9 OP搜索。

小数位数,n,这样任何基数为p的浮点数可以四舍五入到小数位数为n的浮点数,然后在不改变值的情况下再次返回,C17dr§5.2.4.2.11

对于浮动,对其编码的24位有效数字使用p==24。(显式23)。

FLT_DECIMAL_DIG代码

上限(1 pmax*log102)

天花板(1 24* 0.3010...)

天花板(8.224…)

9

厉文栋
2023-03-14

32位浮点数存储在32位中,这意味着不同的值不能超过大约40亿。计算机的速度足以遍历所有数字,因此,对32位浮点数的蛮力搜索可以在可接受的时间内自动进行,并测试所有可能的数字,如果转换为只有8位有效小数的字符串加上从字符串到单精度浮点数表示的逆转换改变了值。

以下短C程序对所有正浮点值执行此操作:

#include <cstdio>
#include <cmath>
#include <limits>
#include <cinttypes>

int main(int argc, char**argv) {
  // Test if conversion with /precision/ significant decimal digit is enough
  int precision = 8;

  // Can override precision = 8 with a command line parameter
  if (argc > 1) {
    precision = strtol(argv[1], nullptr, 0);
    if (precision < 1 || precision > 50) {
      printf("Error: precision should be between 1 and 50, got %d.\n",
             precision);
      exit(1);
    }
  }

  // Buffer length of character buffers to store string representations of
  // floating point numbers with /precision/ significant digits.  /buflen/ is
  // larger than /precision/ because it also needs to store leading zeros,
  // decimal point, sign, scientific notation exponents, and terminating \0.
  const int buflen = precision + 10;

  // storage for current number converted to string with 8 decimal digits
  char str[buflen] = "";

  // shorthands for maxfloat and infinity
  const float maxfloat = std::numeric_limits<float>::max();
  const float inf = std::numeric_limits<float>::infinity();

  // Count the number of times where /precision/ was not sufficient
  uint64_t num_clashes_found = 0;

  // Count all tested floats
  uint64_t num_floats_tested = 0;

  // loop over all positive single precision floating point numbers
  for (float f = 0.0f;               // start with zero
       f <= maxfloat;                // iterate up to and including maxfloat
       ++num_floats_tested,          // count the number of all tested floats
       f = nextafterf(f, inf))       // increment f to next larger float value 
  {
    // convert number to string with /precision/ significant decimal digits
    int numprintedchars = snprintf(str, buflen, "%.*g", precision, f);

    // If string buffer is not long enough to store number as string with
    // /precision/ significant digits, then print warning and terminate program
    if (numprintedchars >= buflen) {
      printf("Buffer length %d is not enough to store \"%.*g\", should"
             " be at least %d\n", buflen, precision, f, numprintedchars+1);
      exit(1);
    }

    // convert the string back to float
    float float_from_string = strtof(str,nullptr);

    // Compare the value
    if (f != float_from_string) {
      printf("%.*g converts to \"%s\" which reads back as %.*g.\n",
             precision+1, f, str, precision+1, float_from_string);
      ++num_clashes_found;
    }
  }
  printf("Found %" PRIu64" clashes when using %d significant decimal digits.\n",
         num_clashes_found, precision);
  printf("Total number of tested floats is %" PRIu64", i.e. with %d significant"
         " decimal digits, we get clashes in %g%% of all numbers.\n",
         num_floats_tested, precision,
         100.0 / num_floats_tested * num_clashes_found);
  return 0;
}

该程序需要大约20分钟来迭代所有正单精度浮点数。

它发现的一个示例数是0.111294314f。当转换为具有8位有效数字的十进制字符串时,结果为“0.11129431”。下一个较小的单精度浮点数是0.111294307f,当转换为只有8位有效数字的字符串时,它具有相同的十进制表示。

总的来说,该程序计算出大约有21.4亿正浮点数,但其中只有大约3200万需要9位有效十进制数字来明确表示。这相当于需要9位数字的所有数字的1.5%,这解释了为什么手动测试不太可能找到它们:

很明显,人们会手动测试十进制表示以数字1开头的浮点值,因为对于这些浮点值,与前面以数字9开头的非常相似的值相比,前导1需要一个更有效的十进制数字。但是,也有10的幂,没有转换为十进制的浮点值1.xxx*10^yy存在,实际上需要9个有效数字。8个有效数字始终足够的10的幂是(给出10的指数,上面命名为yy):-34, -31, -21, -18, -15, -12, -09, -06, -05, -03, 00, 07, 08, 10, 13, 16, 19, 22, 25, 28。如果碰巧手动测试这些10的幂附近的值,则找不到积极的结果。这包括10^0,即1.0附近的值,这可能是人类最有可能开始手动搜索的地方。

 类似资料:
  • 本文向大家介绍C#浮点,双精度,十进制,包括了C#浮点,双精度,十进制的使用技巧和注意事项,需要的朋友参考一下 示例 浮动 float是.NET数据类型的别名System.Single。它允许存储IEEE 754单精度浮点数。存在此数据类型mscorlib.dll,每个C#项目在创建它们时都会隐式引用该数据类型。 大致范围:-3.4×10 38至3.4×10 38 十进制精度:6-9个有效数字 记

  • 我是为了好玩而创作的,但我仍然想认真对待它,一个承载各种测试的网站。通过这些测试,我希望收集统计数据。 一些数据将包括测试完成时间的百分比。我可以很容易地计算测试的百分比,但我希望在存储关于完成测试的各种不同值时返回真实数据。 大多数值都是PHP浮点值,所以我的问题是,如果我想要真正的统计数据,我应该在MYSQL中以浮点、双精度或十进制的形式存储它们吗。 我想利用MYSQL的函数,比如和以及。为了

  • 问题内容: 与浮点变量一起使用时出现问题(向下舍入/截断精度部分)。如何正确执行? 游乐场:https : //play.golang.org/p/49TjJwwEdEJ 输出: 我期望的输出是的,但实际产量。 问题答案: 原始问题: Golang中的楼层号不正确 将Math.Floor与float变量一起使用时出现问题(向下舍入/截断精度部分)。我该怎么做呢? 我预计1980 * 0.1 / 1

  • 问题内容: 我正在尝试将以下十六进制字符串转换为“ 41630D54FFF68872”到9988776.0(float-64)。 使用单精度float-32,我可以这样做: 但这会引发:java.lang.NumberFormatException:使用上面的64位十六进制时,Infinite或NaN。 如何将十六进制转换为使用64位IEEE-754编码的双精度浮点数? 谢谢 问题答案: 您需要双

  • 在浮点数字类型的C#参考中,可以看到 的精度为6到9位 的精度为15到17位 的精度为28到29位 在这种情况下,意味着什么,尤其是,如何成为一个范围?由于指数和尾数的位数是固定的,

  • 假设我使用一个32位的浮点数来存储一个位串(不要问)。进一步假设我想将这个浮点数序列化为一个文件(作为一个浮点数),并在序列化之前对浮点数的十进制表示进行银行家四舍五入。当我将浮点数读回程序时,系统会(自然地)将其存储在一个32位的浮点数中,该浮点数尽可能接近序列化的数字。 在银行舍入后,我的序列化浮点数在数字上必须有多精确,才能确保序列化的浮点数在二进制上与读回的浮点数相等?