0

The way I'm doing it right now is:

#include <iostream>
#include <iomanip>
#include <cmath>

int main() {
    double price = 6.35;
    double tick_size = 0.01;

    // Suppose we have to round up
    double rounded = std::ceil(price / tick_size) * tick_size;

    std::cout << std::setprecision(20) << "original = " << price
              << " | rounded = " << rounded << std::endl;
}

Output is:

original = 6.3499999999999996447 | rounded = 6.3500000000000005329

There lies the problem. The actual representation of 6.35 in double is 6.3499999999999996447. But when I round using tick_size I get something else.

My goal is to get exact double representations of those multiples of tick_size. How do I achieve this?

nishantsingh
  • 4,537
  • 5
  • 25
  • 51
  • 2
    "the problem" is your expectations. If you want exact arithmetics you shouldnt use floating points. Why dont you simply use `int factor = price / tick_size;` ? This will be properly "rounded" – 463035818_is_not_an_ai Jul 27 '20 at 11:18
  • Does this answer your question? https://stackoverflow.com/questions/588004/is-floating-point-math-broken – 463035818_is_not_an_ai Jul 27 '20 at 11:20
  • Also (since you are talking about prices): https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency – chtz Jul 27 '20 at 11:39
  • 1
    Related question: [Find float a to closest multiple of float b](https://stackoverflow.com/questions/61769989/find-float-a-to-closest-multiple-of-float-b). – Eric Postpischil Jul 27 '20 at 11:39
  • Observe that the value of `tick_size` is not .01. In the source code `double tick_size = 0.01;`, the literal `0.01` is converted to the `double` format, which produces the nearest representable value, 0.01000000000000000020816681711721685132943093776702880859375 (in your C implementation, which we presume uses IEEE-754 binary64). So even if the rest of your calculations could be done with no arithmetic error, it would be finding multiples of that, not of .01. – Eric Postpischil Jul 27 '20 at 11:44
  • Observe that 6.35 is also not exactly representable in `double`. The nearest representable values are 6.3499999999999996447286321199499070644378662109375 and 6.35000000000000053290705182007513940334320068359375. Since you cannot get 6.35 using `double`, you must accept one of those other values, or you must use something other than the built-in `double` format to solve the problem. Which of these possibilities do you want, and why? – Eric Postpischil Jul 27 '20 at 11:47
  • 1
    Re “My goal is to get exact double representations of those multiples of `tick_size`.”: Note that value of `tick_size` is 5764607523034235•2^−59. That 53-bit significand is odd, which means it cannot be multiplied by any number other than zero or a power of two without producing a significand wider than 53 bits, which would have to be rounded to fit in the `double` format. That means there are **no** exact multiples of `tick_size` representable in the `double` format other than zero and `tick_size` multiplied by a power of two. – Eric Postpischil Jul 27 '20 at 11:50
  • Floating-point numbers are not real numbers. Much of the intuition you've gained over the years working with numbers in the real world is wrong when you're working with floating-point numbers. Just as there is no exact integer representation for 3/2, there is no exact binary floating-point (for example, IEEE-754, which is almost certainly what your system uses) for 0.01. – Pete Becker Jul 27 '20 at 12:46
  • Instead of "round up", how about "round to nearest'. then `double rounded = std::round(price / tick_size) * tick_size;`. Problem cases are more often then at the half-way point rather then near the desired answer. – chux - Reinstate Monica Jul 28 '20 at 00:01
  • user3286661, Perhaps post an example use of the rounded number. – chux - Reinstate Monica Jul 28 '20 at 13:39

0 Answers0