如何获得两个双精度值的准确除法结果,其中一个能够被另一个整除?

huangapple go评论60阅读模式
英文:

How to get accurate result of two double value division if one is divisible by another?

问题

如果已知一个双精度值可以被另一个整除(即,在数学中a/b得到一个整数),如何在C++中获取准确的整数结果?[示例代码]

int main(int argc, char* argv[]) {
  double price = 1235.1;
  double step = 0.1;
  // 输出 12350,期望输出 12351
  std::cout << int(price/step) << std::endl;

  price = 1235.2;
  step = 0.1;
  // 输出 12352,正确
  std::cout << int(price/step) << std::endl;
};

示例代码链接

英文:

If one double value is already known divisible by another(that is, a/b gives an integer in mathmatics), how can I get the accurate integer result in C++? example code

int main(int argc, char* argv[]) {
  double price = 1235.1;
  double step = 0.1;
  // prints 12350, 12351 expected
  std::cout &lt;&lt; int(price/step) &lt;&lt; std::endl;

  price = 1235.2;
  step = 0.1;
  // prints 12352, ok
  std::cout &lt;&lt; int(price/step) &lt;&lt; std::endl;
};

答案1

得分: 4

以下是您要翻译的内容:

To answer your exact question:

> If one double value is already known divisible by another (that is, a/b gives an integer in mathematics), how can I get the accurate integer result in C++?

You just divide them by each other exactly as you would naively expect.

#include <iostream>
#include <iomanip> //std::setprecision

int main()
{
    std::cout << std::setprecision(20);

    //2^7, aka 128, exactly representable in double precision
    constexpr double price = 2.0 * 2.0 * 2.0 * 2.0 * 2.0 * 2.0 * 2.0;
    std::cout << price << " = 2.0^7 exact\n";

    //(1/2)^4, aka 1/16, aka 0.0625, exactly representable in double precision
    constexpr double step = 0.5 * 0.5 * 0.5 * 0.5;
    std::cout << step << " = 0.5^4 exact\n";

    //(2^7)/((1/2)^4), exactly representable in double precision
    constexpr double d_result = price / step;
    std::cout << d_result << " = (2^7)/((1/2)^4) exact\n";

    // as an integer
    constexpr int i_result = d_result;
    std::cout << i_result << " = 2048 exact\n";

    //there is no difference between d_result and i_result
    constexpr double difference = d_result - i_result;
    static_assert(difference == 0.0);
}

This compiles, so the static assert establishes there is no difference between the integer representation and the double representation.

It prints:

128 = 2.0^7 exact
0.0625 = 0.5^4 exact
2048 = (2^7)/((1/2)^4) exact
2048 = 2048 exact

The reason this doesn't work for you:

Your doubles are known to not be evenly divisible by each other because the value of step is not 0.1, it is 0.100000001490116119, which is the 64-bit floating-point number closest to the real number 1/10.

If you want exactness like this, use a data type with exact representation, e.g., instead of storing dollars as a double, store cents as an integer. (Or use a library that provides arbitrary precision rational numbers. GMP is a popular choice when LGPL is an acceptable license)

英文:

To answer your exact question:

> If one double value is already known divisible by another(that is, a/b gives an integer in mathmatics), how can I get the accurate integer result in C++?

You just divide them by each other exactly as you would naively expect.

#include &lt;iostream&gt;
#include &lt;iomanip&gt; //std::setprecision

int main()
{
    std::cout &lt;&lt; std::setprecision(20);

    //2^7, aka 128, exactly representable in double precision
    constexpr double price = 2.0*2.0*2.0*2.0*2.0*2.0*2.0; 
    std::cout &lt;&lt; price &lt;&lt; &quot; = 2.0^7 exact\n&quot;;

    //(1/2)^4, aka 1/16, aka 0.0625, exactly representable in double precision
    constexpr double step = 0.5*0.5*0.5*0.5;
    std::cout &lt;&lt; step &lt;&lt; &quot; = 0.5^4 exact\n&quot;;

    //(2^7)/((1/2)^4), exactly representable in double precision
    constexpr double d_result = price/step;
    std::cout &lt;&lt; d_result &lt;&lt; &quot; = (2^7)/((1/2)^4) exact\n&quot;;

    // as an integer
    constexpr int i_result = d_result;
    std::cout &lt;&lt; i_result &lt;&lt; &quot; = 2048 exact\n&quot;;

    //there is no difference between d_result and i_result
    constexpr double difference = d_result - i_result;
    static_assert(difference == 0.0);
}

This compiles, so the static assert establishes there is no difference between the integer representation and the double representation.

It prints:

128 = 2.0^7 exact
0.0625 = 0.5^4 exact
2048 = (2^7)/((1/2)^4) exact
2048 = 2048 exact

The reason this doesn't work for you:

Your doubles are known to not be evenly divisible by each other, because the value of step is not 0.1, it is 0.100000001490116119, which is the 64bit floating point number closest to real number 1/10.

If you want exactness like this, use a data type with exact representation, e.g. instead of storing dollars as a double, store cents as an integer. (Or use a library that provides arbitrary precision rational numbers. GMP is a popular choice when LGPL is an acceptable license)

答案2

得分: 2

你不需要。浮点数不是精确的。如果你想要精确的算术运算,请不要使用浮点数。如评论中所提到的,你可以使用int cents而不是float dollars

然而,将其转换为int会截断小数部分,因此,只要提供的(int)price % (int) step == 0,且两者都为正数,你可以通过以下方式获得所需的输出:

std::cout << int((price+step*0.5)/step) << std::endl;
英文:

You don't. Floating point numbers are not exact. If you want exact arithmetics do not use floating point numbers. As mentioned in a comment, rather than float dollars you can work with int cents.

However, conversion to int truncates the fractional part, hence, provided (int)price % (int) step == 0 and both are positive you can get the desired output via:

std::cout &lt;&lt; int((price+step*0.5)/step) &lt;&lt; std::endl;

huangapple
  • 本文由 发表于 2023年4月17日 17:08:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76033458.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定