2

I have operation like this:

const amount = 100;
const rate = 0.32123;

const a = amount * rate;
a // 32.123000000000005
const b = a / rate;
b // 100.00000000000001

I need numbers to be the same after convert. How can i achieve this? Both way convert is required. I have many currencies. Each currency have convert rate for internal currency (lets call it myCurr). I cannot convert immediately one currency into another (except internal) because i have convert ratings only for internal currency. So i need firstly convert currency A to internal currency (A * rate1) then i need to convert A to target currency by dividing it to rate2. But doing so, sometimes leads to lose precision. Is there any alternative for amount * rate1 / rate2?

  • Javascript uses IEEE-754 binary64. The error in each operation will be at most one part in 2^53. The combined error in `amount * rate / rate` will be at most (1+2^−53)^2−1, which is very slightly more than one part in 2^52. If `amount` is quantized—meaning it cannot be any arbitrary value but must be a multiple of some minimum amount of currency (such as one ten-thousandth of a dollar or other currency) and cannot be too large (so that it is never more than, say, 2^50, around a quadrillion, of those units), then the result can be rounded to recover the original value. – Eric Postpischil May 12 '20 at 21:35
  • Note that if `amount` is intended allow fractions, such as 0.01 for pennies when the currency is dollars, then it already contains a rounding error that should be accounted for in application design, as 0.01 cannot be represented in IEEE-754 binary64. Also note the above comment applies **only** to perform one multiplication and one division in succession. If there are other operations, the error analysis is more complicated. – Eric Postpischil May 12 '20 at 21:36

2 Answers2

0

You can never make sure a floating point number stays the same after using it with any arithmetic operation and its reverse operation.

The reason for this:

Floats cover a huge range of numbers - that is why they are way less precise than integers.

Consequences

  • If you want precision, use whole numbers (round them), if not, use floats.

  • Never compare if two floating point numbers are equal. If you compare them, check if they are close. Define a maximum tolerance. If the difference of the numbers is smaller than this tolerance, consider the numbers equal. (Math.abs(amount - b) <= tolerance)

finnmglas
  • 1,626
  • 4
  • 22
  • 37
  • that is one of the reasons why in java, you will always use the `equals()` method rather than comparing two numbers directly – finnmglas May 12 '20 at 20:45
  • 1
    Re “You can never make sure a floating point number stays the same after using it with any arithmetic operation and its reverse operation”: This is too broad. It is possible to do exact arithmetic with floating-point. This may be a niche use and require knowledge and skill that is not often employed, but it is possible, and IEEE-754 is intended to support it (hence the “inexact” exception). – Eric Postpischil May 12 '20 at 21:23
  • 1
    Re “they are way less precise than integers”: This is not an accurate statement. For example, when dividing 4 by 3, integer arithmetic will give a result many orders of magnitude less accurate than floating-point. The truth is the rounding issues in floating-point and integer arithmetic are different, but they both have issues, and it is not correct to say one is uniformly more or less accurate than the other. – Eric Postpischil May 12 '20 at 21:25
  • @EricPostpischil That imprecision is partly to blame on knowledge yet to be acquired by me and also on my language skills, thank you very much for helping me improve both ^^ – finnmglas May 12 '20 at 21:29
  • Re “If you compare them, check if they are close”: [This is not suitable advice for general use.](https://stackoverflow.com/questions/56039679/compare-two-float-variables-in-c/56040270#56040270) – Eric Postpischil May 12 '20 at 21:29
-1

you can use Math.floor or double tilde(~~). both of these would get you what you want.

const amount = 100;
const rate = 0.32123;
const a = amount * rate;
const b = a / rate;
const t = ~~b;
const tt = Math.floor(b);
Ahmet Urun
  • 169
  • 3
  • 18
  • 1
    `Math.round()` is better. `Math.floor()` will turn 12.9999999999 into 12 rather than 13. – Barmar May 12 '20 at 20:47
  • 3
    @Barmar that depends on your usage. `Math.round()` should not be used, if to @Zendor18 a difference of `0.1` or less matters. Then he should go for taking the difference and checking if it is smaller than a specific maximal tolerance – finnmglas May 12 '20 at 20:50
  • 4
    @finnmglas That's true if you're comparing values. But the answer here is for generating the result, and `Math.floor()` or `Math.ceil()` can turn a tiny error into a huge error. – Barmar May 12 '20 at 20:52
  • @Barmar thanks for great notes, really appreciated it. – Ahmet Urun May 12 '20 at 21:09