Skip to content

Commit 3c72fe0

Browse files
committed
refactor: simplify scientific notation parsing
1 parent ebc4665 commit 3c72fe0

2 files changed

Lines changed: 41 additions & 27 deletions

File tree

src/numberUtil.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,41 @@ export function isE(number: string | number) {
5959
return !Number.isNaN(Number(str)) && str.includes('e');
6060
}
6161

62-
export function expandScientificNotation(numStr: string) {
63-
const [mantissa, exponent] = numStr.toLowerCase().split('e');
64-
const exp = Number(exponent);
62+
type ParsedScientificNotation = {
63+
decimal: string;
64+
digits: string;
65+
exponent: number;
66+
integer: string;
67+
negative: boolean;
68+
};
69+
70+
function parseScientificNotation(numStr: string): ParsedScientificNotation {
71+
const [mantissa, exponent = '0'] = numStr.toLowerCase().split('e');
6572
const negative = mantissa.startsWith('-');
6673
const unsignedMantissa = negative ? mantissa.slice(1) : mantissa;
6774
const [integer = '0', decimal = ''] = unsignedMantissa.split('.');
6875
const digits = `${integer}${decimal}`.replace(/^0+/, '') || '0';
6976

77+
return {
78+
decimal,
79+
digits,
80+
exponent: Number(exponent),
81+
integer,
82+
negative,
83+
};
84+
}
85+
86+
function expandScientificNotation(parsed: ParsedScientificNotation) {
87+
const { decimal, digits, exponent, integer, negative } = parsed;
88+
7089
if (digits === '0') {
7190
return '0';
7291
}
7392

7493
const integerDigits = integer.replace(/^0+/, '').length;
7594
const leadingDecimalZeros = (decimal.match(/^0*/) || [''])[0].length;
7695
const initialDecimalIndex = integerDigits || -leadingDecimalZeros;
77-
const decimalIndex = initialDecimalIndex + exp;
96+
const decimalIndex = initialDecimalIndex + exponent;
7897

7998
let expanded = '';
8099

@@ -89,6 +108,14 @@ export function expandScientificNotation(numStr: string) {
89108
return `${negative ? '-' : ''}${expanded}`;
90109
}
91110

111+
function getScientificPrecision(parsed: ParsedScientificNotation) {
112+
if (parsed.exponent >= 0) {
113+
return Math.max(0, parsed.decimal.length - parsed.exponent);
114+
}
115+
116+
return Math.abs(parsed.exponent) + parsed.decimal.length;
117+
}
118+
92119
/**
93120
* [Legacy] Convert 1e-9 to 0.000000001.
94121
* This may lose some precision if user really want 1e-9.
@@ -97,16 +124,7 @@ export function getNumberPrecision(number: string | number) {
97124
const numStr: string = String(number);
98125

99126
if (isE(number)) {
100-
const [mantissa, exponent = '0'] = numStr.toLowerCase().split('e');
101-
const decimalMatch = mantissa.match(/\.(\d+)/);
102-
const decimalLength = decimalMatch?.[1]?.length || 0;
103-
const exp = Number(exponent);
104-
105-
if (exp >= 0) {
106-
return Math.max(0, decimalLength - exp);
107-
}
108-
109-
return Math.abs(exp) + decimalLength;
127+
return getScientificPrecision(parseScientificNotation(numStr));
110128
}
111129

112130
return numStr.includes('.') && validateNumber(numStr)
@@ -132,12 +150,11 @@ export function num2str(number: number): string {
132150
);
133151
}
134152

135-
const precision = getNumberPrecision(numStr);
153+
const parsed = parseScientificNotation(numStr);
154+
const precision = getScientificPrecision(parsed);
136155

137156
numStr =
138-
precision > 100
139-
? expandScientificNotation(numStr)
140-
: number.toFixed(precision);
157+
precision > 100 ? expandScientificNotation(parsed) : number.toFixed(precision);
141158
}
142159

143160
return trimNumber(numStr).fullStr;

tests/util.test.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import getMiniDecimal, {
44
toFixed,
55
} from '../src/MiniDecimal';
66
import type { DecimalClass, ValueType } from '../src/MiniDecimal';
7-
import { expandScientificNotation, num2str } from '../src/numberUtil';
7+
import { num2str } from '../src/numberUtil';
88

99
jest.mock('../src/supportUtil');
1010
const { supportBigInt } = require('../src/supportUtil');
@@ -145,14 +145,11 @@ describe('InputNumber.Util', () => {
145145
});
146146

147147
describe('scientific notation', () => {
148-
it('expands fractional mantissas correctly', () => {
149-
expect(expandScientificNotation('0.123e-1')).toEqual('0.0123');
150-
expect(expandScientificNotation('-0.123e-1')).toEqual('-0.0123');
151-
expect(expandScientificNotation('0.00123e2')).toEqual('0.123');
152-
expect(expandScientificNotation('0e5')).toEqual('0');
153-
});
154-
155-
it('keeps num2str behavior correct for normalized numbers', () => {
148+
it('keeps num2str behavior correct', () => {
149+
expect(num2str(0.123e-1)).toEqual('0.0123');
150+
expect(num2str(-0.123e-1)).toEqual('-0.0123');
151+
expect(num2str(0.00123e2)).toEqual('0.123');
152+
expect(num2str(0e5)).toEqual('0');
156153
expect(num2str(1.23e-19)).toEqual(`0.${'0'.repeat(18)}123`);
157154
expect(num2str(-1.23e-20)).toEqual(`-0.${'0'.repeat(19)}123`);
158155
});

0 commit comments

Comments
 (0)