简体   繁体   English

计算 C++ 中浮点数之间的模数

[英]Comput modulo between floating point numbers in C++

I have the following code to compute modulo between two floating point numbers:我有以下代码来计算两个浮点数之间的模数:

auto mod(float x, float denom)
{
    return x>= 0 ? std::fmod(x, denom) : denom + std::fmod(x + 1.0f, denom) - 1.0f;
}

It does only work partially for negative x :它只对负x部分有效:

-8 0
-7.75 0.25
-7.5 0.5
-7.25 0.75
-7 1
-6.75 1.25
-6.5 1.5
-6.25 1.75
-6 2
-5.75 2.25
-5.5 2.5
-5.25 2.75
-5 3
-4.75 -0.75 <== should be 3.25
-4.5 -0.5   <== should be 3.5
-4.25 -0.25 <== should be 3.75
-4 0
-3.75 0.25
-3.5 0.5
-3.25 0.75
-3 1
-2.75 1.25
-2.5 1.5
-2.25 1.75
-2 2
-1.75 2.25
-1.5 2.5
-1.25 2.75
-1 3
-0.75 3.25
-0.5 3.5
-0.25 3.75
0 0

How to fix it for negative x.如何修复负 x。 Denom is assumed to be an integer greater than 0. Note: fmod as is provided by the standard library is broken for x < 0.0f.假设 Denom 是大于 0 的 integer。注意:标准库提供的 fmod 对于 x < 0.0f 是错误的。

x is in the left column, and the output is in the right column, like so: x 在左列,output 在右列,如下所示:

for(size_t k = 0; k != 65; ++k)
{
    auto x = 0.25f*(static_cast<float>(k) - 32);
    printf("%.8g %.8g\n", x, mod(x, 4));
}

Note: fmod as is provided by the standard library is broken for x < 0.0f注意:标准库提供的 fmod 对于 x < 0.0f 是错误的

I guess you want the result to always be a positive value 1 :我想您希望结果始终为正值1

In mathematics, the result of the modulo operation is an equivalence class, and any member of the class may be chosen as representative;在数学中,模运算的结果是等价class,可以选择class中的任何一个成员作为代表; however, the usual representative is the least positive residue , the smallest non-negative integer that belongs to that class (ie, the remainder of the Euclidean division).然而,通常的代表是最小正余数,最小的非负数 integer 属于那个 class(即,欧氏除法的余数)。

The usual workaround was shown in Igor Tadetnik 's comment , but that seems not enough. Igor Tadetnik评论中显示了通常的解决方法,但这似乎还不够。

@IgorTandetnik That worked. @IgorTandetnik 成功了。 Pesky signed zero though, but I guess you cannot do anything about that. Pesky 虽然签名为零,但我想你对此无能为力。

Well, consider this (2, 3) :好吧,考虑这个(2, 3)

auto mod(double x, double denom)
{
    auto const r{ std::fmod(x, denom) };
    return std::copysign(r < 0 ? r + denom : r, 1);
}

1) https://en.wikipedia.org/wiki/Modulo 1) https://en.wikipedia.org/wiki/Modulo
2) https://en.cppreference.com/w/cpp/numeric/math/copysign 2) https://en.cppreference.com/w/cpp/numeric/math/copysign
3) https://godbolt.org/z/fdr9cbsYT 3) https://godbolt.org/z/fdr9cbsYT

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM