@mathigon/fermat
Advanced tools
Comparing version 1.1.10 to 1.1.11
@@ -40,3 +40,4 @@ /** Checks if two numbers are nearly equals. */ | ||
*/ | ||
export declare function toFraction(decimal: number, precision?: number): number[]; | ||
export declare function toFraction(x: number, maxDen?: number, precision?: number): [num: number, den: number] | undefined; | ||
export declare function toMixedNumber(x: number, maxDen?: number, precision?: number): [base: number, num: number, den: number] | undefined; | ||
/** Bounds a number between a lower and an upper limit. */ | ||
@@ -43,0 +44,0 @@ export declare function clamp(x: number, min?: number, max?: number): number; |
@@ -68,2 +68,3 @@ "use strict"; | ||
toFraction: () => toFraction, | ||
toMixedNumber: () => toMixedNumber, | ||
toOrdinal: () => toOrdinal, | ||
@@ -246,17 +247,24 @@ toWord: () => toWord, | ||
} | ||
function toFraction(decimal, precision = PRECISION) { | ||
function toFraction(x, maxDen = 1e3, precision = 1e-12) { | ||
let n = [1, 0]; | ||
let d = [0, 1]; | ||
let a = Math.floor(decimal); | ||
let rem = decimal - a; | ||
while (d[0] <= 1 / precision) { | ||
if (nearlyEquals(n[0] / d[0], precision)) | ||
return [n[0], d[0]]; | ||
const absX = Math.abs(x); | ||
let rem = absX; | ||
while (Math.abs(n[0] / d[0] - absX) > precision) { | ||
const a = Math.floor(rem); | ||
n = [a * n[0] + n[1], n[0]]; | ||
d = [a * d[0] + d[1], d[0]]; | ||
a = Math.floor(1 / rem); | ||
rem = 1 / rem - a; | ||
if (d[0] > maxDen) | ||
return; | ||
rem = 1 / (rem - a); | ||
} | ||
return [decimal, 1]; | ||
if (d[0] === 1 || !nearlyEquals(n[0] / d[0], absX, precision)) | ||
return; | ||
return [sign(x) * n[0], d[0]]; | ||
} | ||
function toMixedNumber(x, maxDen, precision) { | ||
const base = Math.trunc(x); | ||
const fraction = toFraction(Math.abs(x - base), maxDen, precision); | ||
return fraction ? [base, ...fraction] : void 0; | ||
} | ||
function clamp(x, min = -Infinity, max = Infinity) { | ||
@@ -263,0 +271,0 @@ return Math.min(max, Math.max(min, x)); |
@@ -178,17 +178,24 @@ var __defProp = Object.defineProperty; | ||
} | ||
function toFraction(decimal, precision = PRECISION) { | ||
function toFraction(x, maxDen = 1e3, precision = 1e-12) { | ||
let n = [1, 0]; | ||
let d = [0, 1]; | ||
let a = Math.floor(decimal); | ||
let rem = decimal - a; | ||
while (d[0] <= 1 / precision) { | ||
if (nearlyEquals(n[0] / d[0], precision)) | ||
return [n[0], d[0]]; | ||
const absX = Math.abs(x); | ||
let rem = absX; | ||
while (Math.abs(n[0] / d[0] - absX) > precision) { | ||
const a = Math.floor(rem); | ||
n = [a * n[0] + n[1], n[0]]; | ||
d = [a * d[0] + d[1], d[0]]; | ||
a = Math.floor(1 / rem); | ||
rem = 1 / rem - a; | ||
if (d[0] > maxDen) | ||
return; | ||
rem = 1 / (rem - a); | ||
} | ||
return [decimal, 1]; | ||
if (d[0] === 1 || !nearlyEquals(n[0] / d[0], absX, precision)) | ||
return; | ||
return [sign(x) * n[0], d[0]]; | ||
} | ||
function toMixedNumber(x, maxDen, precision) { | ||
const base = Math.trunc(x); | ||
const fraction = toFraction(Math.abs(x - base), maxDen, precision); | ||
return fraction ? [base, ...fraction] : void 0; | ||
} | ||
function clamp(x, min = -Infinity, max = Infinity) { | ||
@@ -1253,2 +1260,3 @@ return Math.min(max, Math.max(min, x)); | ||
toFraction, | ||
toMixedNumber, | ||
toOrdinal, | ||
@@ -1255,0 +1263,0 @@ toWord, |
{ | ||
"name": "@mathigon/fermat", | ||
"version": "1.1.10", | ||
"version": "1.1.11", | ||
"license": "MIT", | ||
@@ -38,3 +38,3 @@ "homepage": "https://mathigon.io/fermat", | ||
"dependencies": { | ||
"@mathigon/core": "1.1.11" | ||
"@mathigon/core": "1.1.12" | ||
}, | ||
@@ -45,10 +45,10 @@ "devDependencies": { | ||
"@typescript-eslint/parser": "6.4.0", | ||
"esbuild": "0.18.17", | ||
"eslint": "8.47.0", | ||
"eslint-plugin-import": "2.28.0", | ||
"esbuild": "0.19.2", | ||
"eslint": "8.48.0", | ||
"eslint-plugin-import": "2.28.1", | ||
"tape": "5.6.6", | ||
"ts-node": "10.9.1", | ||
"tslib": "2.6.2", | ||
"typescript": "5.1.6" | ||
"typescript": "5.2.2" | ||
} | ||
} |
@@ -189,3 +189,3 @@ // ============================================================================ | ||
// ----------------------------------------------------------------------------- | ||
// Rounding, Decimals and Decimals | ||
// Rounding, Decimals and Fractions | ||
@@ -213,20 +213,29 @@ /** Returns the digits of a number n. */ | ||
*/ | ||
export function toFraction(decimal: number, precision = PRECISION) { | ||
let n = [1, 0]; let d = [0, 1]; | ||
let a = Math.floor(decimal); | ||
let rem = decimal - a; | ||
export function toFraction(x: number, maxDen = 1000, precision = 1e-12): [num: number, den: number] | undefined { | ||
let n = [1, 0]; | ||
let d = [0, 1]; | ||
const absX = Math.abs(x); | ||
let rem = absX; | ||
while (d[0] <= 1 / precision) { | ||
if (nearlyEquals(n[0] / d[0], precision)) return [n[0], d[0]]; | ||
while (Math.abs(n[0] / d[0] - absX) > precision) { | ||
const a = Math.floor(rem); | ||
n = [a * n[0] + n[1], n[0]]; | ||
d = [a * d[0] + d[1], d[0]]; | ||
a = Math.floor(1 / rem); | ||
rem = 1 / rem - a; | ||
if (d[0] > maxDen) return; | ||
rem = 1 / (rem - a); | ||
} | ||
// No nice rational representation so return an irrational "fraction" | ||
return [decimal, 1]; | ||
// We get as close as we want with our tolerance, and if that fraction is still good past our computation we return it. | ||
// Otherwise, we return false, meaning we didn't find a good enough rational approximation. | ||
if (d[0] === 1 || !nearlyEquals(n[0] / d[0], absX, precision)) return; | ||
return [sign(x) * n[0], d[0]]; | ||
} | ||
export function toMixedNumber(x: number, maxDen?: number, precision?: number): [base: number, num: number, den: number] | undefined { | ||
const base = Math.trunc(x); | ||
const fraction = toFraction(Math.abs(x - base), maxDen, precision); | ||
return (fraction) ? [base, ...fraction] : undefined; | ||
} | ||
// ----------------------------------------------------------------------------- | ||
@@ -233,0 +242,0 @@ // Simple Operations |
@@ -8,3 +8,3 @@ // ============================================================================= | ||
import tape from 'tape'; | ||
import {numberFormat, parseNumber, scientificFormat, toWord} from '../src'; | ||
import {numberFormat, parseNumber, scientificFormat, toFraction, toMixedNumber, toWord} from '../src'; | ||
@@ -111,1 +111,18 @@ | ||
}); | ||
tape('fractions', (test) => { | ||
test.deepEqual(toFraction(0.333333333333), [1, 3]); | ||
test.deepEqual(toFraction(-0.333333333333), [-1, 3]); | ||
test.deepEqual(toFraction(0.999999999999), undefined); | ||
test.deepEqual(toFraction(0.833333333333), [5, 6]); | ||
test.deepEqual(toFraction(0.171717171717), [17, 99]); | ||
test.deepEqual(toFraction(0.123412341234), undefined); | ||
test.deepEqual(toFraction(0.123412341234, 10000), [1234, 9999]); | ||
test.deepEqual(toMixedNumber(1.333333333333), [1, 1, 3]); | ||
test.deepEqual(toMixedNumber(-1.333333333333), [-1, 1, 3]); | ||
test.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
309610
4459
+ Added@mathigon/core@1.1.12(transitive)
- Removed@mathigon/core@1.1.11(transitive)
Updated@mathigon/core@1.1.12