计算不带库的浮点值的小数位数

Calculate number of decimal places for a float value WITHOUT libraries?

本文关键字:小数 计算      更新时间:2023-10-16

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

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

您最初的想法非常接近,问题是浮点进行舍入,从而使结果不准确。您需要使用阈值,而不是与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可以解决此问题。

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

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

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

小心回旋,而不是截断!

但请注意,对于负数,它可能不会像预期的那样起作用。

我认为您最好计算std::numeric_limits<float>::digits10 - log10(value),因为这是该值的最大小数位数。如果你有东西要格式化数字,你可以格式化到这个精度,去掉后面的零。如果没有格式化值的东西,你可能需要做很多事情:如果你想要好的结果,这种方法显然是不平凡的。