【问题标题】:Calculate number of decimal places for a float value WITHOUT libraries?计算没有库的浮点值的小数位数?
【发布时间】:2012-03-23 17:42:53
【问题描述】:

我需要计算浮点值的小数位数,例如

1234.567 -> 3
2.1233 -> 4
4.2432 -> 4

我最初的想法是:

number = 1234.567;  
...  
while (number - (int)number > 0.0)  
{  
  // Count decimal places  
  ...  
  number *= 10;  
}

但是,这会导致 while 条件下的浮点精度出现问题。唯一安全的解决方法是将浮点数转换为字符串,然后进行基于字符串的小数位数计数。

问题是:我不能使用任何库,无论是第三方库还是 C++ 标准库(由于环境限制)。稍后我知道如何对 char* 进行操作,但是如何在不使用 C++ 库的情况下将我的浮点值转换为字符串(即 char*)?

非常感谢任何帮助。


// 编辑:这是我目前的方法,但仍然不起作用(例如,对于 2.55555)。如何选择合适的阈值?

float abs(float number)  
{  
  return (number > 0.0 ? number : number * -1);  
}  

int round(float number)  
{  
  return (int)(number + 0.5);  
}  

void splitFloat(float* number, int* mantissa, int* exponent)  
{  
  while (abs(*number - round(*number)) > 0.00001)  
  {  
    // *number -= (int)*number; // ???  
    *number *= 10.0;  

    *mantissa = *number;  
    *exponent += 1;  

    cout << "Number: " << *number << ", Mantisse: " << *mantissa << ", Exponent: " << *exponent << endl;  
  }  
}

【问题讨论】:

  • 您尝试做的事情没有任何意义。无论您的外部问题是什么,这可能都不是解决问题的明智方法。
  • 如果您不使用 C++ 标准库,那么您几乎只是在编写 C,而忽略了许多有用的功能。
  • @Jon 的链接是针对使用 D 的问题,但答案不受该语言的限制。
  • @madth3: ...这就是为什么我认为这是一个合法的骗局。

标签: c++ count floating-point digits


【解决方案1】:

您最初的想法非常接近,问题是浮点进行舍入会导致结果不准确。您需要使用阈值而不是与精确的 0.0 进行比较,并且您需要允许 (int) 操作可能会错误地截断,您应该改为四舍五入。您可以在截断前加 0.5 进行舍入。

当位数不再适合 int 时,您也会遇到问题。您可以通过在每一步减去数字的整数部分来提供帮助。

编辑:要选择适当的阈值,请选择要处理的最大小数位数。如果是 4,那么您要输出的最小数字是 0.0001。将您的阈值设为一半,或0.00005。现在,每次将数字乘以 10 时,阈值也乘以 10!

float threshold = 0.00005;
while (abs(*number - round(*number)) > threshold)  
{  
  *number *= 10.0;
  threshold *= 10.0;
  // ...
}

如果您的 float 和 int 都是 32 位,则您不必担心减去 int。这样做会使返回尾数变得更加困难。

另外,我之前打算给你一个警告但忘记了:这只适用于正数。

还有一个警告,float 的值范围非常有限。例如,您可能无法准确表示 1234.5670,最后您会得到一个无关的数字。更改为 double 可以解决这个问题。

【讨论】:

  • 您在截断之前添加 0.5 的想法听起来很有趣,我会尝试一下。但是,您能否澄清“在每一步中减去数字的整数部分”?也许有一个代码示例?谢谢。
  • @Buxme,这很容易 - 在 number *= 10 之前的某个时间做 number -= (int)number,这样你就剩下小数点右边的数字了。
  • 我试图将您的想法与我的代码结合起来(见最初的帖子),但它仍然远未发挥作用。四舍五入似乎工作正常,但我仍然无法选择合适的阈值。
  • @Buxme,我不知道 StackOverflow 是否会在编辑答案时通知您,所以我告诉您 - 我在回答中回答了您的评论。
  • 已经看到了,谢谢。也将阈值乘以成功。但是代码仍然有点不安全。它现在适用于 2.55555,但我拥有的小数位数越多,再次失败的可能性就越大。但我知道这是 C++ 中浮点精度的问题,而不是您的解决方案,我将以这种方式将其标记为已接受。
【解决方案2】:

你最初的想法很好,但你需要假设一个最小的错误:

number = 1234.567;
...
while (fabs(number - round(number) > 0.00001)
{
    // Count decimal places
    ...
   number *= 10;
}

请注意,当您说1234.567 时,计算机可能会说1234.56700000011234.566999999,而您不想计算所有的0 或9。

并且要小心倒圆,而不是截断!

但请注意,负数可能无法按预期工作。

【讨论】:

  • 当二进制舍入将数字置于整数表示的下方而不是上方时,此操作将失败。
  • @MarkRansom - 对!正如您在同时回答中所说,您必须四舍五入。已更正
  • @rodrigo:我知道浮点精度的问题(请参阅我的初始帖子)并且之前阅读过有关使用阈值的信息。但是假设一个好的最小误差是多少?此外,我不能使用任何包含,如 cmath。
【解决方案3】:

我认为您最好计算std::numeric_limits&lt;float&gt;::digits10 - log10(value),因为这是该值将具有的最大十进制数字。如果你有一些东西可以格式化数字,你可以格式化为这个精度并去掉尾随的零。如果没有东西来格式化值,你可能会做很多事情:如果你想要好的结果,这种方法显然很重要。

【讨论】:

  • 可惜环境里没有std或者log10(),我一定要。
  • 好吧,float 中的小数位数不会在使用相同架构的平台之间改变。精心保护的秘密值恰好是 7(IEEE-754 32 位二进制浮点数)。 ...实际上log10(value + 1) 只是在value 中调用十进制整数个数的一种时髦方式(不过我忘记了1)。这不是真正的火箭科学计算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-29
  • 1970-01-01
相关资源
最近更新 更多