@mathigon/fermat
Advanced tools
Comparing version 1.0.8 to 1.0.9
@@ -5,3 +5,2 @@ var __defProp = Object.defineProperty; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); | ||
var __export = (target, all) => { | ||
@@ -11,15 +10,11 @@ for (var name in all) | ||
}; | ||
var __reExport = (target, module2, copyDefault, desc) => { | ||
if (module2 && typeof module2 === "object" || typeof module2 === "function") { | ||
for (let key of __getOwnPropNames(module2)) | ||
if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default")) | ||
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable }); | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return target; | ||
return to; | ||
}; | ||
var __toCommonJS = /* @__PURE__ */ ((cache) => { | ||
return (module2, temp) => { | ||
return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp); | ||
}; | ||
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0); | ||
var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2); | ||
@@ -77,2 +72,3 @@ // src/index.ts | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
@@ -538,2 +534,3 @@ // src/arithmetic.ts | ||
// src/xnumber.ts | ||
var FORMAT = /^([0-9\-.]*)([%πkmbtq]?)(\/([0-9\-.]+))?([%π]?)$/; | ||
var XNumber = class { | ||
@@ -549,15 +546,11 @@ constructor(num, den, unit) { | ||
} | ||
toString() { | ||
let num = `${numberFormat(this.num, 6)}`; | ||
if (this.den !== void 0) | ||
num = `${num}/${numberFormat(this.den, 6)}`; | ||
if (this.unit === "\u03C0") { | ||
if (num === "1") | ||
return "\u03C0"; | ||
if (num === "0") | ||
return "0"; | ||
if (num === "\u20131") | ||
return "\u2013\u03C0"; | ||
} | ||
return `${num}${this.unit ? this.unit : ""}`; | ||
toString(precision = 4) { | ||
let num = numberFormat(this.num, precision); | ||
let unit = this.unit || ""; | ||
const den = this.den ? `/${numberFormat(this.den, precision)}` : ""; | ||
if (num === "0") | ||
unit = ""; | ||
if (unit === "\u03C0" && !this.den && (num === "1" || num === "\u20131")) | ||
num = num.replace("1", ""); | ||
return `${num}${den}${unit}`; | ||
} | ||
@@ -573,9 +566,4 @@ toMathML() { | ||
get value() { | ||
if (this.den !== void 0) | ||
return this.num / this.den; | ||
if (this.unit === "%") | ||
return this.num / 100; | ||
if (this.unit === "\u03C0") | ||
return this.num * Math.PI; | ||
return this.num; | ||
const unit = this.unit === "%" ? 1 / 100 : this.unit === "\u03C0" ? Math.PI : 1; | ||
return this.num * unit / (this.den || 1); | ||
} | ||
@@ -592,3 +580,3 @@ get sign() { | ||
get inverse() { | ||
if (this.den !== void 0) | ||
if (!this.den) | ||
return new XNumber(this.den, this.num); | ||
@@ -601,14 +589,25 @@ return new XNumber(1 / this.num, void 0, this.unit); | ||
static fromString(s) { | ||
s = s.replace(/[\s,]/g, "").replace("\u2013", "-"); | ||
const unit = s.endsWith("%") ? "%" : s.endsWith("\u03C0") ? "\u03C0" : void 0; | ||
if (unit) | ||
s = s.replace(unit, ""); | ||
if (!s.includes("/")) | ||
return isNaN(+s) ? void 0 : new XNumber(+s, void 0, unit); | ||
const [num, den] = s.split("/").map((x) => +x); | ||
if (isNaN(num) || isNaN(den) || nearlyEquals(den, 0)) | ||
s = s.toLowerCase().replace(/[\s,]/g, "").replace("\u2013", "-").replace("pi", "\u03C0"); | ||
const match = s.match(FORMAT); | ||
if (!match) | ||
return; | ||
let suffix = match[2] || match[5] || void 0; | ||
let num = match[1] ? +match[1] : void 0; | ||
const den = match[4] ? +match[4] : void 0; | ||
if (suffix === "\u03C0" && (!match[1] || match[1] === "-")) | ||
num = match[1] ? -1 : 1; | ||
if (num === void 0 || isNaN(num)) | ||
return; | ||
const power2 = suffix ? "kmbtq".indexOf(suffix) : -1; | ||
if (power2 >= 0) { | ||
num *= 1e3 ** (power2 + 1); | ||
suffix = void 0; | ||
} | ||
if (den === void 0) | ||
return new XNumber(num, void 0, suffix); | ||
if (isNaN(den) || nearlyEquals(den, 0)) | ||
return; | ||
if (!isInteger(num) || !isInteger(den)) | ||
return new XNumber(num / den, void 0, unit); | ||
return new XNumber(num, den, unit); | ||
return new XNumber(num / den, void 0, suffix); | ||
return new XNumber(num, den, suffix); | ||
} | ||
@@ -643,2 +642,10 @@ static fractionFromDecimal(x, maxDen = 100) { | ||
} | ||
clamp(min, max) { | ||
const v = this.value; | ||
if (min !== void 0 && v < min) | ||
return new XNumber(min); | ||
if (max !== void 0 && v > max) | ||
return new XNumber(max); | ||
return this; | ||
} | ||
add(a) { | ||
@@ -659,7 +666,9 @@ return XNumber.sum(this, a); | ||
b = new XNumber(b); | ||
if (a.num === 0) | ||
return b; | ||
if (a.unit !== b.unit) | ||
return new XNumber(a.value + b.value); | ||
if (a.den === void 0 && b.den === void 0) | ||
if (!a.den && !b.den) | ||
return new XNumber(a.num + b.num, void 0, a.unit); | ||
if (a.den === void 0) | ||
if (!a.den) | ||
[a, b] = [b, a]; | ||
@@ -1214,3 +1223,2 @@ if (!isInteger(b.num)) | ||
}; | ||
module.exports = __toCommonJS(src_exports); | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -466,2 +466,3 @@ var __defProp = Object.defineProperty; | ||
// src/xnumber.ts | ||
var FORMAT = /^([0-9\-.]*)([%πkmbtq]?)(\/([0-9\-.]+))?([%π]?)$/; | ||
var XNumber = class { | ||
@@ -477,15 +478,11 @@ constructor(num, den, unit) { | ||
} | ||
toString() { | ||
let num = `${numberFormat(this.num, 6)}`; | ||
if (this.den !== void 0) | ||
num = `${num}/${numberFormat(this.den, 6)}`; | ||
if (this.unit === "\u03C0") { | ||
if (num === "1") | ||
return "\u03C0"; | ||
if (num === "0") | ||
return "0"; | ||
if (num === "\u20131") | ||
return "\u2013\u03C0"; | ||
} | ||
return `${num}${this.unit ? this.unit : ""}`; | ||
toString(precision = 4) { | ||
let num = numberFormat(this.num, precision); | ||
let unit = this.unit || ""; | ||
const den = this.den ? `/${numberFormat(this.den, precision)}` : ""; | ||
if (num === "0") | ||
unit = ""; | ||
if (unit === "\u03C0" && !this.den && (num === "1" || num === "\u20131")) | ||
num = num.replace("1", ""); | ||
return `${num}${den}${unit}`; | ||
} | ||
@@ -501,9 +498,4 @@ toMathML() { | ||
get value() { | ||
if (this.den !== void 0) | ||
return this.num / this.den; | ||
if (this.unit === "%") | ||
return this.num / 100; | ||
if (this.unit === "\u03C0") | ||
return this.num * Math.PI; | ||
return this.num; | ||
const unit = this.unit === "%" ? 1 / 100 : this.unit === "\u03C0" ? Math.PI : 1; | ||
return this.num * unit / (this.den || 1); | ||
} | ||
@@ -520,3 +512,3 @@ get sign() { | ||
get inverse() { | ||
if (this.den !== void 0) | ||
if (!this.den) | ||
return new XNumber(this.den, this.num); | ||
@@ -529,14 +521,25 @@ return new XNumber(1 / this.num, void 0, this.unit); | ||
static fromString(s) { | ||
s = s.replace(/[\s,]/g, "").replace("\u2013", "-"); | ||
const unit = s.endsWith("%") ? "%" : s.endsWith("\u03C0") ? "\u03C0" : void 0; | ||
if (unit) | ||
s = s.replace(unit, ""); | ||
if (!s.includes("/")) | ||
return isNaN(+s) ? void 0 : new XNumber(+s, void 0, unit); | ||
const [num, den] = s.split("/").map((x) => +x); | ||
if (isNaN(num) || isNaN(den) || nearlyEquals(den, 0)) | ||
s = s.toLowerCase().replace(/[\s,]/g, "").replace("\u2013", "-").replace("pi", "\u03C0"); | ||
const match = s.match(FORMAT); | ||
if (!match) | ||
return; | ||
let suffix = match[2] || match[5] || void 0; | ||
let num = match[1] ? +match[1] : void 0; | ||
const den = match[4] ? +match[4] : void 0; | ||
if (suffix === "\u03C0" && (!match[1] || match[1] === "-")) | ||
num = match[1] ? -1 : 1; | ||
if (num === void 0 || isNaN(num)) | ||
return; | ||
const power2 = suffix ? "kmbtq".indexOf(suffix) : -1; | ||
if (power2 >= 0) { | ||
num *= 1e3 ** (power2 + 1); | ||
suffix = void 0; | ||
} | ||
if (den === void 0) | ||
return new XNumber(num, void 0, suffix); | ||
if (isNaN(den) || nearlyEquals(den, 0)) | ||
return; | ||
if (!isInteger(num) || !isInteger(den)) | ||
return new XNumber(num / den, void 0, unit); | ||
return new XNumber(num, den, unit); | ||
return new XNumber(num / den, void 0, suffix); | ||
return new XNumber(num, den, suffix); | ||
} | ||
@@ -571,2 +574,10 @@ static fractionFromDecimal(x, maxDen = 100) { | ||
} | ||
clamp(min, max) { | ||
const v = this.value; | ||
if (min !== void 0 && v < min) | ||
return new XNumber(min); | ||
if (max !== void 0 && v > max) | ||
return new XNumber(max); | ||
return this; | ||
} | ||
add(a) { | ||
@@ -587,7 +598,9 @@ return XNumber.sum(this, a); | ||
b = new XNumber(b); | ||
if (a.num === 0) | ||
return b; | ||
if (a.unit !== b.unit) | ||
return new XNumber(a.value + b.value); | ||
if (a.den === void 0 && b.den === void 0) | ||
if (!a.den && !b.den) | ||
return new XNumber(a.num + b.num, void 0, a.unit); | ||
if (a.den === void 0) | ||
if (!a.den) | ||
[a, b] = [b, a]; | ||
@@ -594,0 +607,0 @@ if (!isInteger(b.num)) |
@@ -0,9 +1,10 @@ | ||
declare type Suffix = '%' | 'π' | undefined; | ||
/** Extended Number class. */ | ||
export declare class XNumber { | ||
unit?: "%" | "π" | undefined; | ||
unit?: Suffix; | ||
num: number; /** Used for all number types (decimals, fractions, units, ...). */ | ||
den?: number; /** Only used for fractions and always ≥ 0. */ | ||
constructor(num: number, den?: number, unit?: "%" | "π" | undefined); | ||
constructor(num: number, den?: number, unit?: Suffix); | ||
valueOf(): number; | ||
toString(): string; | ||
toString(precision?: number): string; | ||
toMathML(): string; | ||
@@ -26,2 +27,3 @@ /** | ||
static fractionFromDecimal(x: number, maxDen?: number): XNumber; | ||
clamp(min?: number, max?: number): XNumber; | ||
add(a: XNumber | number): XNumber; | ||
@@ -40,1 +42,2 @@ subtract(a: XNumber | number): XNumber; | ||
} | ||
export {}; |
{ | ||
"name": "@mathigon/fermat", | ||
"version": "1.0.8", | ||
"version": "1.0.9", | ||
"license": "MIT", | ||
@@ -38,12 +38,12 @@ "homepage": "https://mathigon.io/fermat", | ||
"@types/tape": "4.13.2", | ||
"@typescript-eslint/eslint-plugin": "5.13.0", | ||
"@typescript-eslint/parser": "5.13.0", | ||
"esbuild": "0.14.23", | ||
"eslint": "8.10.0", | ||
"@typescript-eslint/eslint-plugin": "5.17.0", | ||
"@typescript-eslint/parser": "5.17.0", | ||
"esbuild": "0.14.30", | ||
"eslint": "8.12.0", | ||
"eslint-plugin-import": "2.25.4", | ||
"tape": "5.5.2", | ||
"ts-node": "10.5.0", | ||
"ts-node": "10.7.0", | ||
"tslib": "2.3.1", | ||
"typescript": "4.6.2" | ||
"typescript": "4.6.3" | ||
} | ||
} |
@@ -11,2 +11,6 @@ // ============================================================================= | ||
const FORMAT = /^([0-9\-.]*)([%πkmbtq]?)(\/([0-9\-.]+))?([%π]?)$/; | ||
type Suffix = '%'|'π'|undefined; | ||
/** Extended Number class. */ | ||
@@ -17,3 +21,3 @@ export class XNumber { | ||
constructor(num: number, den?: number, public unit?: '%'|'π') { | ||
constructor(num: number, den?: number, public unit?: Suffix) { | ||
// Ensure that den is always positive | ||
@@ -28,11 +32,9 @@ this.num = (den !== undefined && den < 0) ? -num : num; | ||
toString() { | ||
let num = `${numberFormat(this.num, 6)}`; | ||
if (this.den !== undefined) num = `${num}/${numberFormat(this.den, 6)}`; | ||
if (this.unit === 'π') { | ||
if (num === '1') return 'π'; | ||
if (num === '0') return '0'; | ||
if (num === '–1') return '–π'; | ||
} | ||
return `${num}${this.unit ? this.unit : ''}`; | ||
toString(precision = 4) { | ||
let num = numberFormat(this.num, precision); | ||
let unit = this.unit || ''; | ||
const den = this.den ? `/${numberFormat(this.den, precision)}` : ''; | ||
if (num === '0') unit = ''; | ||
if (unit === 'π' && !this.den && (num === '1' || num === '–1')) num = num.replace('1', ''); | ||
return `${num}${den}${unit}`; | ||
} | ||
@@ -54,6 +56,4 @@ | ||
get value() { | ||
if (this.den !== undefined) return this.num / this.den; | ||
if (this.unit === '%') return this.num / 100; | ||
if (this.unit === 'π') return this.num * Math.PI; | ||
return this.num; | ||
const unit = (this.unit === '%') ? 1/100 : (this.unit === 'π') ? Math.PI : 1; | ||
return this.num * unit / (this.den || 1); | ||
} | ||
@@ -74,3 +74,3 @@ | ||
get inverse() { | ||
if (this.den !== undefined) return new XNumber(this.den, this.num); | ||
if (!this.den) return new XNumber(this.den!, this.num); | ||
return new XNumber(1 / this.num, undefined, this.unit); | ||
@@ -88,15 +88,26 @@ } | ||
static fromString(s: string) { | ||
// Replace whitespace and unit suffixes | ||
s = s.replace(/[\s,]/g, '').replace('–', '-'); | ||
const unit = s.endsWith('%') ? '%' : s.endsWith('π') ? 'π' : undefined; | ||
if (unit) s = s.replace(unit, ''); | ||
s = s.toLowerCase().replace(/[\s,]/g, '').replace('–', '-').replace('pi', 'π'); | ||
const match = s.match(FORMAT); | ||
if (!match) return; | ||
// Handle integers or decimals | ||
if (!s.includes('/')) return isNaN(+s) ? undefined : new XNumber(+s, undefined, unit); | ||
let suffix = (match[2] || match[5] || undefined) as Suffix; | ||
let num = match[1] ? +match[1] : undefined; | ||
const den = match[4] ? +match[4] : undefined; | ||
// Handle fractions | ||
const [num, den] = s.split('/').map(x => +x); | ||
if (isNaN(num) || isNaN(den) || nearlyEquals(den, 0)) return; | ||
if (!isInteger(num) || !isInteger(den)) return new XNumber(num / den, undefined, unit); | ||
return new XNumber(num, den, unit); | ||
// Special handling for π and -π | ||
if (suffix === 'π' && (!match[1] || match[1] === '-')) num = match[1] ? -1 : 1; | ||
if (num === undefined || isNaN(num)) return; | ||
// Handle larger power suffixes | ||
const power = suffix ? 'kmbtq'.indexOf(suffix) : -1; | ||
if (power >= 0) { | ||
num *= 1000 ** (power + 1); | ||
suffix = undefined; | ||
} | ||
// Create XNumber instances | ||
if (den === undefined) return new XNumber(num, undefined, suffix); | ||
if (isNaN(den) || nearlyEquals(den, 0)) return; | ||
if (!isInteger(num) || !isInteger(den)) return new XNumber(num / den, undefined, suffix); | ||
return new XNumber(num, den, suffix); | ||
} | ||
@@ -138,2 +149,9 @@ | ||
clamp(min?: number, max?: number) { | ||
const v = this.value; | ||
if (min !== undefined && v < min) return new XNumber(min); | ||
if (max !== undefined && v > max) return new XNumber(max); | ||
return this; | ||
} | ||
add(a: XNumber|number) { | ||
@@ -158,2 +176,3 @@ return XNumber.sum(this, a); | ||
if (typeof b === 'number') b = new XNumber(b); | ||
if (a.num === 0) return b; | ||
@@ -165,6 +184,6 @@ // If units are different, always convert to a decimal | ||
// Neither a nor b are fractions | ||
if (a.den === undefined && b.den === undefined) return new XNumber(a.num + b.num, undefined, a.unit); | ||
if (!a.den && !b.den) return new XNumber(a.num + b.num, undefined, a.unit); | ||
// Ensure that a is always a fraction | ||
if (a.den === undefined) [a, b] = [b, a]; | ||
if (!a.den) [a, b] = [b, a]; | ||
@@ -171,0 +190,0 @@ // Trying to add a decimal to a fraction. |
@@ -23,3 +23,3 @@ // ============================================================================= | ||
test.equal(n(0, 2, 'π').toString(), '0'); | ||
test.equal(n(10000, 20000).toString(), '10,000/20,000'); | ||
test.equal(n(10000, 20000).toString(), '10k/20k'); | ||
test.end(); | ||
@@ -46,2 +46,3 @@ }); | ||
test.equal(n(1, 2, 'π').add(n(3, 2, 'π')).toString(), '2π'); | ||
test.equal(n(0).add(n(2, undefined, 'π')).toString(), '2π'); | ||
test.end(); | ||
@@ -63,2 +64,5 @@ }); | ||
test.equal(str(' 2/3 π '), '2/3π'); | ||
test.equal(str('π'), 'π'); | ||
test.equal(str('-π'), '–π'); | ||
test.equal(str('-π/2'), '–1/2π'); | ||
test.equal(str('$'), undefined); | ||
@@ -69,2 +73,11 @@ test.equal(str('1,000/3000'), '1,000/3,000'); | ||
tape('XNumber Power Suffixes', (test) => { | ||
test.equal(str('1k'), '1,000'); | ||
test.equal(str('10m'), '10m'); | ||
test.equal(str('1.2m'), '1.2m'); | ||
test.equal(str('1.b'), '1b'); | ||
test.equal(str('.5b'), '500m'); | ||
test.end(); | ||
}); | ||
tape('Decimal to String', (test) => { | ||
@@ -71,0 +84,0 @@ test.equal(dec(0.5), '1/2'); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
287551
4245