如何进行带有偏差的浮点舍入(始终向上或向下舍入)?

发布于 2024-07-15 18:24:30 字数 415 浏览 5 评论 0原文

我想以偏置舍入浮动,要么总是向下,要么总是向上。 代码中有一个特定的点,我需要这个,程序的其余部分应该像往常一样四舍五入到最接近的值。

例如,我想四舍五入到最接近的 1/10 倍数。 最接近 7/10 的浮点数约为 0.69999998807,但最接近 8/10 的浮点数约为 0.80000001192。 当我对数字进行四舍五入时,这是我得到的两个结果。 我宁愿让它们以同样的方式四舍五入。 7/10 应舍入为 0.70000004768,8/10 应舍入为 0.80000001192。

在这个例子中,我总是向上舍入,但我有一些地方我想总是向下舍入。 幸运的是,我在这些地方只处理积极的价值观。

我用来舍入的线是 floor(val * 100 + 0.5) / 100。 我正在用 C++ 编程。

I want to round floats with a bias, either always down or always up. There is a specific point in the code where I need this, the rest of the program should round to the nearest value as usual.

For example, I want to round to the nearest multiple of 1/10. The closest floating point number to 7/10 is approximately 0.69999998807, but the closest number to 8/10 is approximately 0.80000001192. When I round off numbers, these are the two results I get. I'd rather get them rounded the same way. 7/10 should round to 0.70000004768 and 8/10 should round to 0.80000001192.

In this example I am always rounding up, but I have some places where I want to always round down. Fortunately, I am only dealing with positive values in each of these places.

The line I am using to round is floor(val * 100 + 0.5) / 100. I am programming in C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

偏闹i 2024-07-22 18:24:30

我认为实现这一点的最佳方法是依赖这样一个事实:根据 IEEE 754 浮点标准,浮点位的整数表示按字典顺序排序为 2 补码整数。

即,您可以简单地添加一个 ulp(最后一个位置的单位)来获取下一个浮点表示(如果阈值较小,则它总是比您的阈值稍大,因为舍入误差最多为 1/2 ulp),

例如

 float floatValue = 7.f/10;
 std::cout << std::setprecision(20) << floatValue << std::endl;
 int asInt = *(int*)&floatValue;
 asInt += 1;
 floatValue = *(float*)&asInt;
 std::cout << floatValue << std::endl;

打印(在我的系统上)

 0.69999998807907104492
 0.70000004768371582031

要知道何时需要添加一个 ulp,您必须依赖 floor 和圆角 floor 之间的差异,

 if (std::floor(floatValue * 100.) != std::floor(floatValue * 100. + 0.5)) {
    int asInt = *(int*)&floatValue;
    asInt += 1;
    floatValue = *(float*)&asInt;
 }

才能正确转换 0.69..到 0.70.. 但保留 0.80..。

请注意,在应用 floor 之前,通过与 100. 相乘,浮点数会提升为双精度。

如果您不这样做,您可能会面临这样的情况:(

 7.f/10.f * 100.f

精度有限)浮点表示将为 70.00...

I think the best way to achieve this is to rely on the fact that according to the IEEE 754 floating point standard, the integer representation of floating point bits are lexicographically ordered as a 2-complement integer.

I.e. you could simply add one ulp (units in the last place) to get the next floating point representation (which will always be slightly larger than your treshold if it was smaller, since the round error is at most 1/2 ulp)

e.g.

 float floatValue = 7.f/10;
 std::cout << std::setprecision(20) << floatValue << std::endl;
 int asInt = *(int*)&floatValue;
 asInt += 1;
 floatValue = *(float*)&asInt;
 std::cout << floatValue << std::endl;

prints (on my system)

 0.69999998807907104492
 0.70000004768371582031

To know when you need to add one ulp, you'll have to rely on the difference of floor and a rounded floor

 if (std::floor(floatValue * 100.) != std::floor(floatValue * 100. + 0.5)) {
    int asInt = *(int*)&floatValue;
    asInt += 1;
    floatValue = *(float*)&asInt;
 }

Would correctly convert 0.69.. to 0.70.. but leave 0.80.. alone.

Note that the float gets promoted to a double via the multiplication with 100. before the floor is applied.

If you don't do this you risk getting in the situation that for

 7.f/10.f * 100.f

The (limited in precision) float representation would be 70.00...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文