Skip to content

Commit

Permalink
feat(InputNumber): input-number support enableRound (#1922)
Browse files Browse the repository at this point in the history
* feat: input-number support enableRound

* feat: change to places

* feat: change to places

* chore: lint fix

* feat: largeNumberToFixed

* feat: largeNumberToFixed formatDecimal

* feat: formatDecimal
  • Loading branch information
zhangpaopao0609 authored Sep 10, 2024
1 parent fa26c77 commit 4c7c9f8
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 35 deletions.
76 changes: 60 additions & 16 deletions js/input-number/large-number.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import isString from 'lodash/isString';
import isNumber from 'lodash/isNumber';
import isObject from 'lodash/isObject';
import log from '../log/log';

export type InputNumberDecimalPlaces = number | { enableRound: boolean, places: number };

export function fillZero(length: number) {
return new Array(length).fill(0).join('');
}
Expand Down Expand Up @@ -336,38 +339,79 @@ export function largeNumberAdd(num1: string, num2: string): string {
return largePositiveNumberAdd(num1, num2);
}

/**
* 格式化小数,并且可以控制小数点后的位数和是否进行四舍五入。
*
* @param {number} num - 要格式化的数字。
* @param {number} places - 小数点后的位数。
* @param {boolean} rounding - 是否进行四舍五入。
* @returns {string} 格式化后的数字字符串。
*/
export function formatDecimal(num: number, places: number, enableRound: boolean = true) {
// 开启四舍五入 直接用 toFixed
if (enableRound) {
return num.toFixed(places);
}

const [integer, decimal] = num.toString().split('.');
// 保留 0 位小数
if (places === 0) {
return integer;
}
// 补足小数位数
let decimalNumber = decimal.slice(0, places);
if (decimal.length < places) {
decimalNumber += (fillZero(places - decimal.length));
}
return [integer, decimalNumber].join('.');
}

export function decimalPlacesToFixedNum(num: number, decimalPlaces: InputNumberDecimalPlaces) {
if (isObject(decimalPlaces)) {
return formatDecimal(num, decimalPlaces.places, decimalPlaces.enableRound ?? true);
}
return formatDecimal(num, decimalPlaces, true);
}

/**
* 大数保留 N 位小数(没有精度问题)
* @param {String} number 大数(只能使用字符串表示)
* @param {Number} decimalPlaces 保留的小数位数
* @param {Boolean} largeNumber 是否为大数
*/
export function largeNumberToFixed(
number: string | number, decimalPlaces: number = 0, largeNumber = true,
number: string | number,
decimalPlaces: InputNumberDecimalPlaces = 0,
largeNumber: boolean = true,
): string {
if (!largeNumber) return Number(number).toFixed(decimalPlaces);
if (Number.isNaN(Number(number))) return '';
if (!largeNumber) {
return decimalPlacesToFixedNum(Number(number), decimalPlaces);
}
const places = isObject(decimalPlaces) ? decimalPlaces.places : decimalPlaces;
const enableRound = isObject(decimalPlaces) ? (decimalPlaces.enableRound ?? true) : true;
if (!isString(number)) return String(number);
// eslint-disable-next-line prefer-const
let [num1, num2] = number.split('.');
// 如果不存在小数点,则补足位数
if (!num2) {
return decimalPlaces ? [number, (fillZero(decimalPlaces))].join('.') : number;
return (places > 0 && enableRound) ? [number, (fillZero(places))].join('.') : number;
}
// 存在小数点,保留 0 位小数,四舍五入
if (decimalPlaces === 0) {
return Number(num2[0]) >= 5 ? largePositiveNumberAdd(num1, '1') : num1;
// 存在小数点,保留 0 位小数,灵活配置四舍五入
if (places === 0) {
return (enableRound && Number(num2[0]) >= 5) ? largePositiveNumberAdd(num1, '1') : num1;
}
// 存在小数点,保留 > 0 位小数,四舍五入(此时,整数位不会发生任何变化,只需关注小数位数)
let decimalNumber = num2.slice(0, decimalPlaces);
if (num2.length < decimalPlaces) {
decimalNumber += (fillZero(decimalPlaces - num2.length));
} else {
// 存在小数点,保留 > 0 位小数,灵活配置四舍五入
let decimalNumber = num2.slice(0, places);
if (num2.length < places) {
decimalNumber += (fillZero(places - num2.length));
} else if (enableRound) {
// 用于判断是否处于 1.08 这种小数为0开始的边界情况
const leadZeroNum = decimalNumber.match(/^0+/)?.[0].length;
// 用于判断是否处于 0.99/1.99 等需要往非0位进位的场景
const leadNineNum = decimalNumber.match(/^9+/);
// 决定是否需要四舍五入
const needAdded = Number(num2[decimalPlaces]) >= 5;
const needAdded = Number(num2[places]) >= 5;

// 四舍五入后的结果
decimalNumber = needAdded
Expand All @@ -378,16 +422,16 @@ export function largeNumberToFixed(
if (
leadZeroNum
&& needAdded
&& leadZeroNum + decimalNumber.length >= decimalPlaces
&& leadZeroNum + decimalNumber.length >= places
) {
decimalNumber = `${fillZero(
decimalPlaces - decimalNumber.length
places - decimalNumber.length
)}${decimalNumber}`;
}
// 边界场景2:(0.99 这种可能进位的边界情况):计算后有误判的可能,如995 四舍五入后需进位
if (leadNineNum && decimalNumber.length > decimalPlaces) {
if (leadNineNum && decimalNumber.length > places) {
num1 = (Number(num1) + 1).toString();
decimalNumber = fillZero(decimalPlaces);
decimalNumber = fillZero(places);
}
}
return [num1, decimalNumber].join('.');
Expand Down
3 changes: 2 additions & 1 deletion js/input-number/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
largeNumberSubtract,
} from './large-number';
import log from '../log';
import type { InputNumberDecimalPlaces } from './large-number';

export * from './large-number';

Expand Down Expand Up @@ -240,7 +241,7 @@ export function canSetValue(number: string, lastNumber: number) {
export function formatUnCompleteNumber(
number: string,
extra: {
decimalPlaces?: number;
decimalPlaces?: InputNumberDecimalPlaces;
largeNumber?: boolean;
isToFixed?: boolean;
} = {}
Expand Down
41 changes: 41 additions & 0 deletions test/unit/input-number/formatDecimal.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { formatDecimal, decimalPlacesToFixedNum } from '../../../js/input-number/large-number';

describe('formatDecimal', () => {
it('1, 0, true', () => {
expect(formatDecimal(1, 0, true)).toBe('1');
});

it('1, 0, false', () => {
expect(formatDecimal(1, 0, false)).toBe('1');
});

it('1.5, 0, true', () => {
expect(formatDecimal(1.5, 0, true)).toBe('2');
});

it('1.5, 0, false', () => {
expect(formatDecimal(1.5, 0, false)).toBe('1');
});

it('1.3456, 2, true', () => {
expect(formatDecimal(1.3456, 2, true)).toBe('1.35');
});

it('1.3456, 2, false', () => {
expect(formatDecimal(1.3456, 2, false)).toBe('1.34');
});

it('1.3, 2, false', () => {
expect(formatDecimal(1.3, 2, false)).toBe('1.30');
});
});

describe('decimalPlacesToFixedNum', () => {
it('1.3456, 2, true', () => {
expect(decimalPlacesToFixedNum(1.3456, 2)).toBe('1.35');
});

it('1.3456, 2, false', () => {
expect(decimalPlacesToFixedNum(1.3456, { places: 2, enableRound: false })).toBe('1.34');
});
});
34 changes: 16 additions & 18 deletions test/unit/input-number/largeNumberToFixed.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,31 @@ describe('largeNumberToFixed', () => {
});

it('1.087', () => {
expect(largeNumberToFixed('1.087', 2, true)).toBe(
'1.09'
);
expect(largeNumberToFixed('1.087', 2, true)).toBe('1.09');
});

it('1.0095', () => {
expect(largeNumberToFixed('1.0095', 3, true)).toBe(
'1.010'
);
expect(largeNumberToFixed('1.0095', 3, true)).toBe('1.010');
});

it('0.996', () => {
expect(largeNumberToFixed('0.996', 2, true)).toBe(
'1.00'
);
expect(largeNumberToFixed('0.996', 2, true)).toBe('1.00');
});
it('1.985', () => {
expect(largeNumberToFixed('1.985', 2, true)).toBe(
'1.99'
);
expect(largeNumberToFixed('1.985', 3, true)).toBe(
'1.985'
);
expect(largeNumberToFixed('1.985', 2, true)).toBe('1.99');
expect(largeNumberToFixed('1.985', 3, true)).toBe('1.985');
});
it('1.99', () => {
expect(largeNumberToFixed('1.99', 1, true)).toBe(
'2.0'
);
expect(largeNumberToFixed('1.99', 1, true)).toBe('2.0');
});
it('{ enableRound: boolean; places: number; }', () => {
expect(largeNumberToFixed('1', { places: 0, enableRound: false })).toBe('1');
expect(largeNumberToFixed('1', { places: 0 })).toBe('1');
expect(largeNumberToFixed('1', { places: 0, enableRound: false }, false)).toBe('1');
expect(largeNumberToFixed('1', { places: 0 }, false)).toBe('1');
expect(largeNumberToFixed('1.3456', { places: 1, enableRound: false })).toBe('1.3');
expect(largeNumberToFixed('1.3456', { places: 2, enableRound: false })).toBe('1.34');
expect(largeNumberToFixed('1.3456', { places: 1 })).toBe('1.3');
expect(largeNumberToFixed('1.3456', { places: 2 })).toBe('1.35');
});
});

0 comments on commit 4c7c9f8

Please sign in to comment.