Skip to content

Commit

Permalink
feat: use reduce instead of recursion & add resolve undefined and null
Browse files Browse the repository at this point in the history
  • Loading branch information
careteenL committed Dec 15, 2019
1 parent 8ab4f95 commit ba57696
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 68 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ NP.times(3, 0.3); // = 0.9, not 0.8999999999999999
NP.times(0.362, 100); // = 36.2, not 36.199999999999996
NP.divide(1.21, 1.1); // = 1.1, not 1.0999999999999999
NP.round(0.105, 2); // = 0.11, not 0.1

// undefined
NP.plus(0.1, 0.2, undefined); // = 0.3
NP.plus(0.1, 0.2, null); // = 0.3
NP.minus(1.0, 0.9, undefined); // = 0.1
NP.times(3, 0.3, undefined); // = 0.9
NP.divide(1.21, 1.1, null); // = 1.1
```

PS: If you want to get rid of `XXX is beyond boundary when transfer to integer, the results may not be accurate`, use this at the beginning of your app to turn off boundary checking.
Expand Down
33 changes: 23 additions & 10 deletions build/index.iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,12 @@ function times(num1, num2) {
/**
* 精确加法
*/
function plus(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
}
var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
function plus(nums) {
resolveNums(nums);
return nums.reduce(function (sum, cur) {
var baseNum = Math.pow(10, Math.max(digitLength(sum), digitLength(cur)));
return (times(sum, baseNum) + times(cur, baseNum)) / baseNum;
}, 0);
}
/**
* 精确减法
Expand Down Expand Up @@ -125,6 +121,23 @@ function enableBoundaryChecking(flag) {
if (flag === void 0) { flag = true; }
_boundaryCheckingState = flag;
}
function isUndef(v) {
return v === undefined || v === null;
}
/**
* 将数组中`undefined`和`null`类型转换为`0`并`warn`
*/
function resolveNums(nums) {
if (!Array.isArray(nums)) {
nums = [nums];
}
for (var index = 0; index < nums.length; index++) {
if (isUndef(nums[index])) {
console.warn(index + " of " + nums + " is not a number");
nums[index] = 0;
}
}
}
var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };

exports.strip = strip;
Expand Down
33 changes: 23 additions & 10 deletions build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,12 @@ function times(num1, num2) {
/**
* 精确加法
*/
function plus(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
}
var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
function plus(nums) {
resolveNums(nums);
return nums.reduce(function (sum, cur) {
var baseNum = Math.pow(10, Math.max(digitLength(sum), digitLength(cur)));
return (times(sum, baseNum) + times(cur, baseNum)) / baseNum;
}, 0);
}
/**
* 精确减法
Expand Down Expand Up @@ -126,6 +122,23 @@ function enableBoundaryChecking(flag) {
if (flag === void 0) { flag = true; }
_boundaryCheckingState = flag;
}
function isUndef(v) {
return v === undefined || v === null;
}
/**
* 将数组中`undefined`和`null`类型转换为`0`并`warn`
*/
function resolveNums(nums) {
if (!Array.isArray(nums)) {
nums = [nums];
}
for (var index = 0; index < nums.length; index++) {
if (isUndef(nums[index])) {
console.warn(index + " of " + nums + " is not a number");
nums[index] = 0;
}
}
}
var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };

exports.strip = strip;
Expand Down
2 changes: 1 addition & 1 deletion build/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 23 additions & 10 deletions build/index.umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,12 @@ function times(num1, num2) {
/**
* 精确加法
*/
function plus(num1, num2) {
var others = [];
for (var _i = 2; _i < arguments.length; _i++) {
others[_i - 2] = arguments[_i];
}
if (others.length > 0) {
return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
}
var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
function plus(nums) {
resolveNums(nums);
return nums.reduce(function (sum, cur) {
var baseNum = Math.pow(10, Math.max(digitLength(sum), digitLength(cur)));
return (times(sum, baseNum) + times(cur, baseNum)) / baseNum;
}, 0);
}
/**
* 精确减法
Expand Down Expand Up @@ -128,6 +124,23 @@ function enableBoundaryChecking(flag) {
if (flag === void 0) { flag = true; }
_boundaryCheckingState = flag;
}
function isUndef(v) {
return v === undefined || v === null;
}
/**
* 将数组中`undefined`和`null`类型转换为`0`并`warn`
*/
function resolveNums(nums) {
if (!Array.isArray(nums)) {
nums = [nums];
}
for (var index = 0; index < nums.length; index++) {
if (isUndef(nums[index])) {
console.warn(index + " of " + nums + " is not a number");
nums[index] = 0;
}
}
}
var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };

exports.strip = strip;
Expand Down
96 changes: 59 additions & 37 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,57 +47,59 @@ function checkBoundary(num: number) {
}

/**
* 精确乘法
* 精确加法
*/
function times(num1: number, num2: number, ...others: number[]): number {
if (others.length > 0) {
return times(times(num1, num2), others[0], ...others.slice(1));
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
const baseNum = digitLength(num1) + digitLength(num2);
const leftValue = num1Changed * num2Changed;

checkBoundary(leftValue);

return leftValue / Math.pow(10, baseNum);
function plus(...args: any[]) {
const [first, ...nums] = [...args];
resolveNums(nums, 0);
return nums.reduce((ret, cur) => {
const baseNum = Math.pow(10, Math.max(digitLength(ret), digitLength(cur)));
return (times(ret, baseNum) + times(cur, baseNum)) / baseNum;
}, first);
}

/**
* 精确加法
* 精确减法
*/
function plus(num1: number, num2: number, ...others: number[]): number {
if (others.length > 0) {
return plus(plus(num1, num2), others[0], ...others.slice(1));
}
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
function minus(...args: any[]) {
const [first, ...nums] = [...args];
resolveNums(nums, 0);
return nums.reduce((ret, cur) => {
const baseNum = Math.pow(10, Math.max(digitLength(ret), digitLength(cur)));
return (times(ret, baseNum) - times(cur, baseNum)) / baseNum;
}, first);
}

/**
* 精确减法
* 精确乘法
*/
function minus(num1: number, num2: number, ...others: number[]): number {
if (others.length > 0) {
return minus(minus(num1, num2), others[0], ...others.slice(1));
}
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
function times(...args: any[]) {
const [first, ...nums] = [...args];
resolveNums(nums, 1);
return nums.reduce((ret, cur) => {
const num1Changed = float2Fixed(ret);
const num2Changed = float2Fixed(cur);
const baseNum = digitLength(ret) + digitLength(cur);
const leftValue = num1Changed * num2Changed;
checkBoundary(leftValue);
return leftValue / Math.pow(10, baseNum);
}, first);
}

/**
* 精确除法
*/
function divide(num1: number, num2: number, ...others: number[]): number {
if (others.length > 0) {
return divide(divide(num1, num2), others[0], ...others.slice(1));
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
// fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
return times((num1Changed / num2Changed), strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
function divide(...args: any[]) {
const [first, ...nums] = [...args];
resolveNums(nums, 1);
return nums.reduce((ret, cur) => {
const num1Changed = float2Fixed(ret);
const num2Changed = float2Fixed(cur);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
// fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
return times((num1Changed / num2Changed), strip(Math.pow(10, digitLength(cur) - digitLength(ret))));
}, first);
}

/**
Expand All @@ -116,5 +118,25 @@ let _boundaryCheckingState = true;
function enableBoundaryChecking(flag = true) {
_boundaryCheckingState = flag;
}

function isUndef(v: any): boolean {
return v === undefined || v === null;
}

/**
* 将数组中`undefined`和`null`类型转换为`0/1`并`warn`
*/
function resolveNums(nums: number | number[], ret: number = 0) {
if (!Array.isArray(nums)) {
nums = [nums];
}
for (let index = 0; index < nums.length; index++) {
if (isUndef(nums[index])) {
console.warn(`${index} of ${nums} is not a number`);
nums[index] = ret;
}
}
}

export { strip, plus, minus, times, divide, round, digitLength, float2Fixed, enableBoundaryChecking };
export default { strip, plus, minus, times, divide, round, digitLength, float2Fixed, enableBoundaryChecking };
11 changes: 11 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ test('NP.plus can do plus operation', (t) => {
t.true(NP.plus(1.6e-30, 1.6e-30) === 3.2e-30);

t.true(NP.plus(0.1, 0.2, 0.3) === 0.6);
t.true(NP.plus(0.1, 0.2, 0.3, undefined) === 0.6); // undefined
t.true(NP.plus(0.1, 0.2, 0.3, null) === 0.6); // null
});

test('NP.minus can do minus operation', (t) => {
Expand All @@ -69,6 +71,9 @@ test('NP.minus can do minus operation', (t) => {

t.true(NP.minus(6, 3, 2) === 1);
t.true(NP.minus(6, 3, 2, 1, 2, 3) === -5);

t.true(NP.minus(6, 3, 2, undefined) === 1); // undefined
t.true(NP.minus(6, 3, 2, null) === 1); // null
});

test('NP.times can do times operation', (t) => {
Expand Down Expand Up @@ -98,6 +103,9 @@ test('NP.times can do times operation', (t) => {

t.true(NP.times(0.000000123456, 0.000000123456) === 1.5241383936e-14);
t.true(NP.times(1.23456e-7, 1.23456e-7) === 1.5241383936e-14);

t.true(NP.times(2, 2, 3, undefined) === 12); // undefined
t.true(NP.times(2, 2, 3, null) === 12); // null
});

test('NP.divide can do divide operation', (t) => {
Expand All @@ -123,6 +131,9 @@ test('NP.divide can do divide operation', (t) => {
t.true(NP.divide(33.3333, 100) === 0.333333);
t.true(NP.divide(83.42894732749, 100) === 0.8342894732749);
t.true(NP.divide(1, 3) === 0.3333333333333333);

t.true(NP.divide(12, 3, 2, undefined) === 2); // undefined
t.true(NP.divide(12, 3, 2, null) === 2); // null
});

test('NP.round can do round operation', (t) => {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"strict": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"downlevelIteration": true,
"lib": [
"dom",
"es5",
Expand Down

0 comments on commit ba57696

Please sign in to comment.