Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save adrian-green/e54c71e84b1af0786b6c811fba089d96 to your computer and use it in GitHub Desktop.
Save adrian-green/e54c71e84b1af0786b6c811fba089d96 to your computer and use it in GitHub Desktop.
A function to assist in MidpointRounding.AwayFromZero in Javascript
Math.RoundAwayFromZero = function round(num, decimalPlaces) {
const d = decimalPlaces || 2;
const m = Math.pow(10, d);
const n = +(d ? num * m : num).toFixed(8);
const i = Math.ceil(n), f = n - i;
const e = 1e-8;
const r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 === 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
}
@adrian-green
Copy link
Author

adrian-green commented Aug 23, 2023

Program.cs

using System;

namespace ConsoleApplication1
{
    internal class Program
    {
        public static int NextInt32(Random rng)
        {
            int firstBits = rng.Next(0, 1 << 4) << 28;
            int lastBits = rng.Next(0, 1 << 28);
            return firstBits | lastBits;
        }
        public static decimal NextDecimalSample(Random random)
        {
            var sample = 1m;
            while (sample >= 1)
            {
                var a = NextInt32(random);
                var b = NextInt32(random);
                //The high bits of 0.9999999999999999999999999999m are 542101086.
                var c = random.Next(542101087);
                sample = new Decimal(a, b, c, false, 28);
            }
            return sample;
        }

        public static decimal NextDecimal(Random random)
        {
            return NextDecimal(random, decimal.MaxValue);
        }

        public static decimal NextDecimal(Random random, decimal maxValue)
        {
            return NextDecimal(random, decimal.Zero, maxValue);
        }

        public static decimal NextDecimal(Random random, decimal minValue, decimal maxValue)
        {
            var nextDecimalSample = NextDecimalSample(random);
            return maxValue * nextDecimalSample + minValue * (1 - nextDecimalSample);
        }
        public static void Main(string[] args)
        {
            const int decimals = 2;
            var random = new Random();
            for (var i = 0; i < 100000; i++)
            {
                var sample = Math.Round(NextDecimal(random, 100), 4);
                var result = Math.Round(sample, decimals, MidpointRounding.AwayFromZero);
                Console.WriteLine(sample + "|" + result);
            }
        }
    }
}

Math_Round_AwayFromZero.js

const fs = require("fs");


const data = fs.readFileSync("test_data").toString();

Math.RoundAwayFromZero = function round(num, decimalPlaces) {
    const d = decimalPlaces || 2;
    const m = Math.pow(10, d);
    const n = +(d ? num * m : num).toFixed(8);
    const i = Math.ceil(n), f = n - i;
    const e = 1e-8;
    const r = (f > 0.5 - e && f < 0.5 + e) ?
        ((i % 2 === 0) ? i : i + 1) : Math.round(n);
    return d ? r / m : r;
}


const test_data_lines = data.split("\n");
for (var line in test_data_lines) {
    let sample = Number(test_data_lines[line].split("|")[0]);
    let result = Number(test_data_lines[line].split("|")[1]);
    if (isNaN(result)) {
        continue;
    }
    let test_result = Math.RoundAwayFromZero(sample, 2);
    if (test_result !== result) {
        console.log("Test failed:", sample, test_result, result);
        break;
    }
}
console.log(line, " Tests passed");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment