我需要计算浮点值的小数位数,例如
1234. 567 - > 3
2. 1233 - > 4
4. 2432 - > 4
我最初的想法是:
number = 1234.567;
...
while (number - (int)number > 0.0)
{
// Count decimal places
...
number *= 10;
}
但是,这会导致while条件下浮点精度出现问题。唯一安全的解决方法是从float转换为字符串,然后执行基于字符串的小数位计数。
问题是:我不得使用任何库,无论是第三方还是C ++标准库(由于环境限制)。我知道如何在char *上操作,但是如何在不使用C ++库的情况下将我的float值转换为字符串(即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 :(得分:6)
你最初的想法非常接近,问题是浮点会进行舍入,从而使结果不准确。您需要使用阈值而不是精确地比较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
会解决此问题。
答案 1 :(得分:1)
您最初的想法很好,但您需要承担最小错误:
number = 1234.567;
...
while (fabs(number - round(number) > 0.00001)
{
// Count decimal places
...
number *= 10;
}
请注意,当您说1234.567
时,计算机可能会说1234.5670000001
或1234.566999999
并且您不想计算0或9的所有数据。
谨防改变,而不是截断!
但请注意,负数可能无法正常工作。
答案 2 :(得分:0)
我认为你最好计算std::numeric_limits<float>::digits10 - log10(value)
,因为这是该值的最大小数位数。如果您要格式化数字,可以格式化为此精度并去除尾随零。如果没有什么东西可以格式化这个值,你可能会做很多事情:如果你想获得好的结果,这种方法显然是非平凡的。