Profectus/src/util/break_eternity.ts

196 lines
6.1 KiB
TypeScript

import projInfo from "data/projInfo.json";
import type { DecimalSource } from "lib/break_eternity";
import Decimal from "lib/break_eternity";
export default Decimal;
const decimalOne = new Decimal(1);
export function exponentialFormat(num: DecimalSource, precision: number, mantissa = true): string {
let e = Decimal.log10(num).floor();
let m = Decimal.div(num, Decimal.pow(10, e));
if (m.toStringWithDecimalPlaces(precision) === "10") {
m = decimalOne;
e = e.add(1);
}
const eString = e.gte(1e9)
? format(e, Math.max(Math.max(precision, 3), projInfo.defaultDecimalsShown))
: e.gte(10000)
? commaFormat(e, 0)
: e.toStringWithDecimalPlaces(0);
if (mantissa) {
return m.toStringWithDecimalPlaces(precision) + "e" + eString;
} else {
return "e" + eString;
}
}
export function commaFormat(num: DecimalSource, precision: number): string {
if (num === null || num === undefined) {
return "NaN";
}
num = new Decimal(num);
if (num.mag < 0.001) {
return (0).toFixed(precision);
}
const init = num.toStringWithDecimalPlaces(precision);
const portions = init.split(".");
portions[0] = portions[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
if (portions.length == 1) return portions[0];
return portions[0] + "." + portions[1];
}
export function regularFormat(num: DecimalSource, precision: number): string {
if (num === null || num === undefined) {
return "NaN";
}
num = new Decimal(num);
if (num.mag < 0.0001) {
return (0).toFixed(precision);
}
if (num.mag < 0.1 && precision !== 0) {
precision = Math.max(
Math.max(precision, num.log10().negate().ceil().toNumber()),
projInfo.defaultDecimalsShown
);
}
return num.toStringWithDecimalPlaces(precision);
}
const eeee1000 = new Decimal("eeee1000");
const e100000 = new Decimal("e100000");
const e1000 = new Decimal("e1000");
const e9 = new Decimal(1e9);
const e6 = new Decimal(1e6);
const e3 = new Decimal(1e3);
const nearOne = new Decimal(0.98);
const thousandth = new Decimal(0.001);
const zero = new Decimal(0);
export function format(num: DecimalSource, precision?: number, small?: boolean): string {
if (precision == null) precision = projInfo.defaultDecimalsShown;
small = small ?? projInfo.defaultShowSmall;
num = new Decimal(num);
if (isNaN(num.sign) || isNaN(num.layer) || isNaN(num.mag)) {
return "NaN";
}
if (num.sign < 0) {
return "-" + format(num.neg(), precision);
}
if (num.mag === Number.POSITIVE_INFINITY) {
return "Infinity";
}
if (num.gte(eeee1000)) {
const slog = num.slog();
if (slog.gte(e6)) {
return "F" + format(slog.floor());
} else {
return (
Decimal.pow(10, slog.sub(slog.floor())).toStringWithDecimalPlaces(3) +
"F" +
commaFormat(slog.floor(), 0)
);
}
} else if (num.gte(e100000)) {
return exponentialFormat(num, 0, false);
} else if (num.gte(e1000)) {
return exponentialFormat(num, 0);
} else if (num.gte(e9)) {
return exponentialFormat(num, precision);
} else if (num.gte(e3)) {
return commaFormat(num, 0);
} else if (num.gte(thousandth) || !small) {
return regularFormat(num, precision);
} else if (num.eq(zero)) {
return (0).toFixed(precision);
}
num = invertOOM(num);
if (num.lt(e1000)) {
const val = exponentialFormat(num, precision);
return val.replace(/([^(?:e|F)]*)$/, "-$1");
} else {
return format(num, precision) + "⁻¹";
}
}
export function formatWhole(num: DecimalSource): string {
num = new Decimal(num);
if (num.sign < 0) {
return "-" + formatWhole(num.neg());
}
if (num.gte(e9)) {
return format(num);
}
if (num.lte(nearOne) && !num.eq(zero)) {
return format(num);
}
return format(num, 0);
}
export function formatTime(seconds: DecimalSource): string {
if (Decimal.lt(seconds, 0)) {
return "-" + formatTime(Decimal.neg(seconds));
}
if (Decimal.gt(seconds, 2 ** 51)) {
// integer precision limit
return format(Decimal.div(seconds, 31536000)) + "y";
}
seconds = new Decimal(seconds).toNumber();
if (seconds < 60) {
return format(seconds) + "s";
} else if (seconds < 3600) {
return formatWhole(Math.floor(seconds / 60)) + "m " + format(seconds % 60) + "s";
} else if (seconds < 86400) {
return (
formatWhole(Math.floor(seconds / 3600)) +
"h " +
formatWhole(Math.floor(seconds / 60) % 60) +
"m " +
formatWhole(seconds % 60) +
"s"
);
} else if (seconds < 31536000) {
return (
formatWhole(Math.floor(seconds / 84600) % 365) +
"d " +
formatWhole(Math.floor(seconds / 3600) % 24) +
"h " +
formatWhole(Math.floor(seconds / 60) % 60) +
"m"
);
} else {
return (
formatWhole(Math.floor(seconds / 31536000)) +
"y " +
formatWhole(Math.floor(seconds / 84600) % 365) +
"d " +
formatWhole(Math.floor(seconds / 3600) % 24) +
"h"
);
}
}
export function toPlaces(x: DecimalSource, precision: number, maxAccepted: DecimalSource): string {
x = new Decimal(x);
let result = x.toStringWithDecimalPlaces(precision);
if (new Decimal(result).gte(maxAccepted)) {
result = Decimal.sub(maxAccepted, Math.pow(0.1, precision)).toStringWithDecimalPlaces(
precision
);
}
return result;
}
// Will also display very small numbers
export function formatSmall(x: DecimalSource, precision?: number): string {
return format(x, precision, true);
}
export function invertOOM(x: DecimalSource): Decimal {
let e = Decimal.log10(x).ceil();
const m = Decimal.div(x, Decimal.pow(10, e));
e = e.neg();
x = new Decimal(10).pow(e).times(m);
return x;
}