1

I'm working on a project where I have an input field where a user puts in a dollar amount and depending on the frequency they would like to pay it divides that amount by said value (2, 4, or 12). So for instance if I put in an amount of $5 and had the frequency set at 2, I would have it display $2.50 for the charge amount. The issue I am having is if a user inputs $20.27 with frequency set at 2, I would expect to see $10.14 as the display but for some reason am getting $10.13 even after using Math.round and a toFixed(2). If I input $2.27 or $0.27 I do get the expected $1.14 and $.14 respectively but as soon as I get to more than $10 it no longer rounds correctly. I cannot figure out what I am doing wrong. Here is my code:

const setAmount = (num) => {
        scope.selectAmount(selectedAmount / num);
        finalAmount = ((Math.round(selectedAmount * 100) / 100) / num).toFixed(2);
        selectedAmountText = '$' + finalAmount;
        $('#pay-schedule span').text(selectedAmountText);

    }

Any help would be tremendously appreciated. Thanks!

5
  • it breaks - in what way? Commented Aug 9, 2021 at 22:40
  • It breaks in the sense that it starts rounding back down to $x.13 instead of $x.14 for the $x.27 example. Commented Aug 9, 2021 at 22:42
  • If you input $4.27, it rounds to $2.14. If you input $10.27, it rounds to $5.13. Commented Aug 9, 2021 at 22:43
  • Do you always want it to round up? Commented Aug 9, 2021 at 23:01
  • I just always want it to round to the appropriate whole decimal amount in cents. So when the raw amount comes in as $2.135 (from the above example) I would like it to appropriately round to $2.14. If the result of dividing the input number was $2.132, I would expect it to round to $2.13. Commented Aug 9, 2021 at 23:30

4 Answers 4

2

Change the ordering as follows:

finalAmount = ((Math.round(selectedAmount / num * 100) / 100)).toFixed(2);

Dividing later messes things up.

Sign up to request clarification or add additional context in comments.

Comments

1

I don't have an exact explanation for this but dividing by 2 at the end makes it somewhat inconsistent. So diving the number by 2 in the first place solves the issue for the specific values that you've provided.

function round(num) {
  let val = num / 2
  return (Math.round(val * 100) / 100).toFixed(2);
}

Comments

0

I'm not sure why you need toFixed().

var amount=20.27;
var frequency=2;
var finalamount=amount/frequency;
finalamountrounded=Math.round(finalamount * 100) / 100
console.log(finalamountrounded)

produces

10.14

Comments

0

The issue is, that the number 20.27 does not exists. On input it is rounded to the nearest possible value:

var a = 20.27;
a.toFixed(18) // output: "20.269999999999999574"
var b = a/2;
b.toFixed(18); // output: "10.134999999999999787"

I use toFixed(18) because it shows all relevant digits. From this point of view, 10.13 is the correct and expected value.

Rounding with Math.round(b*100)/100 may solve this example, but can produce other errors. Here b*100 is rounded to the next whole integer. And in this case, dividing is by 100 returns a value >10.14 (not =10.14).

c = Math.round(b*100);
c.toFixed(18); // output: "1014.000000000000000000"
(c/100).toFixed(18); // output: "10.140000000000000568"

This numerical problem is common with all languages, that support IEEE floating point numbers. That the reason, that financial software uses cents or e.g. BCD (binary coded decimals) numbers. And that is the reason, that the old programming language COBOL is used for many financial programs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.