简体   繁体   中英

Rounding a number in Javascript so that it matches C#

I have an application written in nodejs. The application needs to calculate a maritime levy. the calculation needs to match the result from the port. The levy calculator in the port is written in C#.

NOTE: I Have no control over the C# code. I need to adapt the JS code around what C# is returning

This is the Javascript code:

console.log('Testing rounding -- js')
nrt = 34622
c = 0

if (nrt <= 5000) c = nrt * 0.405
else if (nrt > 5000 && nrt <= 20000) c = 2025 + ( (nrt - 5000) * 0.291)
else if (nrt > 20000 && nrt <= 50000) c = 6390 + ( (nrt - 20000) * 0.24)
else c = 13590 + ( (nrt - 50000) * 0.18)

var p = nrt * 0.1125

var t = c + p

console.log(t)
console.log(t.toFixed(2))

Result:

Testing rounding -- js
13794.255
13794.25

This is the C# code:

using System;

namespace sample1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Testing rounding -- csharp");

            decimal nrt = 34622;
            decimal  c = 0;
            if (nrt <= 5000) c = nrt * (decimal) 0.405;
            else if (nrt > 5000 && nrt <= 20000) c = 2025 + ( (nrt - 5000) * (decimal) 0.291);
            else if (nrt > 20000 && nrt <= 50000) c = 6390 + ( (nrt - 20000) * (decimal) 0.24);
            else c = 13590 + ( (nrt - 50000) * (decimal) 0.18);

            decimal p = nrt * (decimal) 0.1125;

            decimal t = c + p;

            Console.WriteLine(t);
            Console.WriteLine(Decimal.Round(t, 2));
        }
    }
}

Result:

Testing rounding -- csharp
13794.2550
13794.26

Please note that I don't know C# at all. I realise that it has a "decimal" type, which is a 128-bit data type suitable for financial and monetary calculations. It has 28-29 digit Precision

As far as I know, Javascript doesn't handle a 128-bit data type.

I also wonder whether the problem might well be in different implementation of rounding.

I am writing this as I also add that 13794.2550 is spectacularly hard to round reliably across systems. This is a whole different rabbit hole.

But, for example using a rounding function blatantly stolen from stackoverflow :

function r(n, decimals) {
    return Number((Math.round(n + "e" + decimals)  + "e-" + decimals));
}

console.log(r(13794.2550,2))
console.log(13794.2550.toFixed(2))

Result:

13794.26 <--- this is what I want! But, is it reliable?
13794.25

The rounding function seems to give out the same result. So, maybe I am having a "rounding implementation" problem, rather than a "not enough precision" problem. But, is it reliable?

(That is, is the c# Decimal.Round function implemented exactly as the rounding function blatantly stolen from stackoverflow ?

I think the issue you are getting is because you are using different type of rounding functions.

In the JS section you are using toFixed() rather than Math.round() . toFixed isn't exactly the same as C# rounding. It's more similar to the C# rounding where you add an AwayFromZero property to it. You can do this in C# as well but have to be explicit about it about it --> Math.Round(value, 2, MidpointRounding.AwayFromZero); . You should be able to use Math.round() to get the same results as you would in C#. They are both Maintained by Microsoft, so generally they work very similar and sometimes have the same implementations of libraries (from a user perspective).

Math.round(num) vs num.toFixed(0) and browser inconsistencies

So yes that second implementation that you used is reliable. If you are worried about the 128 byte conversion, trying using double instead of decimal and check if you have the same results as double is 64 bit, and if you need further testing use float which is 32 bit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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