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); + }); + }); });