我想将楼层号截断为 3 位十进制数。例:
input : x = 0.363954;
output: 0.364
我用了
double myCeil(float v, int p)
{
return int(v * pow(float(10),p))/pow(float(10),p );
}
但是输出是0.3630001
.我试图使用<cmath>
trunc
,但它不存在。
浮点数学通常使用二进制表示形式;因此,有些十进制值不能完全表示为浮点值。试图摆弄内部精度就遇到了这个问题。但大多数情况下,当有人尝试这样做时,他们实际上是在尝试使用特定的精度显示值,这很简单:
double x = 0.363954;
std::cout.precision(3);
std::cout << x << 'n';
你要找的函数是std::ceil
,而不是std::trunc
double myCeil(double v, int p)
{
return std::ceil(v * std::pow(10, p)) / std::pow(10, p);
}
根据需要以std::floor
或std::round
替换myFloor
或myRound
。 (请注意,std::round
显示在 C++11 中,如果尚未启用,则必须启用(。
不可能准确地得到 0.364。您无法将数字 0.364 (364/1000( 完全存储为浮点数,就像您需要无限个小数才能将 1/3 写为 0.3333333333...
你做对了,除了你可能想使用 std::round(( 来舍入到最接近的数字,而不是 int((,它会修剪。
比较浮点数是一项棘手的工作。通常,您能做的最好的事情就是检查数字是否彼此足够接近。
您是否出于比较目的进行四舍五入?在这种情况下,您似乎对 3 位小数感到满意(这取决于所讨论的每个问题......(,在这种情况下,为什么不只是
bool are_equal_to_three_decimals(double a, double b)
{
return std::abs(a-b) < 0.001;
}
请注意,通过比较四舍五入的数字和我建议的函数获得的结果并不等效!
这是一个旧帖子,但你要求的是二进制数学的十进制精度。 两者之间的转换给你一个明显的区别。
我认为,你的主要观点是关于恒等的,这样你就可以使用两个数字之间的相等/不等式比较。
由于我们人类使用的(十进制(和计算机使用的(二进制(之间存在差异,因此我们有三个选择。
-
我们使用十进制库。这在计算上是昂贵的,因为我们使用的数学与计算机的工作方式不同。有几种,有一天它们可能会被性病收养。参见例如"ISO/IEC JTC1 SC22 WG21 N2849">
-
我们学习用二进制进行数学运算。这在精神上是昂贵的,因为这不是我们正常做数学的方式。
-
我们更改算法以包含身份测试。
-
我们更改算法以使用差异测试。
对于选项 3,我们可以决定一个数字需要与另一个数字有多接近才能被视为"相同数字"。
一种简单的方法是(如上面的@SirGuy给出的(我们使用天花板或地板作为测试 - 这很好,因为它允许我们选择我们感兴趣的大量数字。 它是特定于领域的,如果使用 2 的幂而不是 10 的幂,他给出的解决方案可能会更优化一些。
您肯定只想在使用相等/不等式检验时进行计算。
所以现在,我们的相等性测试将是(对于 10 个二进制位置(近 3dp((
// Normal identity test for floats.
// Quick but fails eg 1.0000023 == 1.0000024
return (a == b);
变为(2^10 = 1024(。
// Modified identity test for floats.
// Works with 1.0000023 == 1.0000024
return (std::floor(a * 1024) == std::floor(b * 1024));
但这并不好我会选择选项 4。假设您认为任何小于 0.001 的差值都是微不足道的,例如 1.00012 = 1.00011。
这执行额外的减法和符号去除,这比位移便宜得多(也更可靠(。
// Modified equality test for floats.
// Returns true if the ∂ is less than 1/10000.
// Works with 1.0000023 == 1.0000024
return abs(a - b) < 0.0001;
这归结为您关于计算循环性的评论,我建议您计算两个圆之间的增量(差值(,而不是测试等价性。但这并不完全是你在问题中问的......