typia
Version:
Superfast runtime validators with only one line
70 lines (61 loc) • 2.26 kB
text/typescript
export interface _IDecimal {
coefficient: bigint;
exponent: number;
}
export interface _IDecimalRatio {
numerator: bigint;
denominator: bigint;
}
export const _decimalDecompose = (value: number): _IDecimal | null => {
if (Number.isFinite(value) === false) return null;
const [mantissa = "0", exponentText = "0"] = value.toString().split("e");
const negative: boolean = mantissa.startsWith("-");
const unsigned: string = negative ? mantissa.slice(1) : mantissa;
const point: number = unsigned.indexOf(".");
const decimals: number = point === -1 ? 0 : unsigned.length - point - 1;
const digits: bigint = BigInt(unsigned.replace(".", ""));
return {
coefficient: negative ? -digits : digits,
exponent: Number(exponentText) - decimals,
};
};
export const _decimalDivide = (
value: number,
divisor: _IDecimal,
): _IDecimalRatio | null => {
const dividend: _IDecimal | null = _decimalDecompose(value);
if (dividend === null || divisor.coefficient === BigInt(0)) return null;
const exponent: number = dividend.exponent - divisor.exponent;
return exponent >= 0
? {
numerator: dividend.coefficient * _decimalPower(exponent),
denominator: divisor.coefficient,
}
: {
numerator: dividend.coefficient,
denominator: divisor.coefficient * _decimalPower(-exponent),
};
};
export const _decimalIntegerStep = (value: number): _IDecimal | null => {
const decimal: _IDecimal | null = _decimalDecompose(value);
if (decimal === null || decimal.coefficient <= BigInt(0)) return null;
if (decimal.exponent >= 0)
return {
coefficient: decimal.coefficient * _decimalPower(decimal.exponent),
exponent: 0,
};
const denominator: bigint = _decimalPower(-decimal.exponent);
return {
coefficient:
decimal.coefficient / _decimalGcd(decimal.coefficient, denominator),
exponent: 0,
};
};
export const _decimalToNumber = (value: _IDecimal): number =>
Number(`${value.coefficient}e${value.exponent}`);
export const _decimalPower = (exponent: number): bigint =>
BigInt(10) ** BigInt(exponent);
export const _decimalGcd = (x: bigint, y: bigint): bigint => {
while (y !== BigInt(0)) [x, y] = [y, x % y];
return x < BigInt(0) ? -x : x;
};