From 791c05e1fcface02c88514e862883ec39d594472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Mon, 20 Apr 2020 17:12:54 -0700 Subject: [PATCH] Add "toFloatRatio" helper method (#1750) Add a numerically-naive method for calculating the floating point ratio between grain values, as it is needed in #1743. Following discussion in [this review], we hope that @wchargin will re-write this method later to have better precision. Test plan: Attached unit tests should pass. [this review]: https://github.com/sourcecred/sourcecred/pull/1715#discussion_r396909459 Paired with @hammadj --- src/grain/grain.js | 12 ++++++++++++ src/grain/grain.test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/grain/grain.js b/src/grain/grain.js index b957daa..71559c7 100644 --- a/src/grain/grain.js +++ b/src/grain/grain.js @@ -139,3 +139,15 @@ export function multiplyFloat(grain: Grain, num: number): Grain { export function fromApproximateFloat(f: number): Grain { return multiplyFloat(ONE, f); } + +/** + * Approximates the division of two grain values + * + * This naive implementation of grain division converts the given values + * to floats and performs simple floating point division. + * + * Do not assume this will be precise! + */ +export function toFloatRatio(numerator: Grain, denominator: Grain): number { + return Number(numerator) / Number(denominator); +} diff --git a/src/grain/grain.test.js b/src/grain/grain.test.js index 3ee1c04..08ac73d 100644 --- a/src/grain/grain.test.js +++ b/src/grain/grain.test.js @@ -7,6 +7,7 @@ import { ZERO, fromApproximateFloat, multiplyFloat, + toFloatRatio, } from "./grain"; describe("src/grain/grain", () => { @@ -117,4 +118,32 @@ describe("src/grain/grain", () => { expect(fromApproximateFloat(0.1)).toEqual(ONE / 10n); }); }); + + describe("toFloatRatio", () => { + it("handles a one-to-one ratio", () => { + expect(toFloatRatio(ONE, ONE)).toEqual(1); + }); + it("handles a larger numerator", () => { + // $ExpectFlowError + expect(toFloatRatio(ONE * 2n, ONE)).toEqual(2); + }); + it("handles fractional numbers", () => { + // $ExpectFlowError + expect(toFloatRatio(ONE * 5n, ONE * 2n)).toEqual(2.5); + }); + it("calculates repeating decimal ratios", () => { + // $ExpectFlowError + expect(toFloatRatio(ONE * 5n, ONE * 3n)).toEqual(5 / 3); + }); + it("approximates correctly when Grain values are not exactly equal", () => { + // $ExpectFlowError + const almostOne = ONE - 1n; + expect(toFloatRatio(ONE, almostOne)).toEqual(1); + }); + it("handles irrational numbers", () => { + const bigPi = multiplyFloat(ONE, Math.PI); + // $ExpectFlowError + expect(toFloatRatio(bigPi, ONE * 2n)).toEqual(Math.PI / 2); + }); + }); });