From a07b2f9408feca0e000729be7e2a3bc17851b23b Mon Sep 17 00:00:00 2001 From: MiniPear Date: Fri, 18 Jun 2021 14:33:29 +0800 Subject: [PATCH] fix: pretty wilkinson-extended with precision problem close: #156 (#157) * fix: pretty wilkinson-extended with precision problem close: #156 * chore: update test coverage * chore: update version --- .../tick-methods/wilkinson-extended.spec.ts | 7 ++++++- __tests__/unit/utils/add.spec.ts | 13 ------------ package.json | 2 +- src/tick-methods/wilkinson-extended.ts | 11 +++++++--- src/utils/precision-add.ts | 20 ------------------- 5 files changed, 15 insertions(+), 38 deletions(-) delete mode 100644 __tests__/unit/utils/add.spec.ts delete mode 100644 src/utils/precision-add.ts diff --git a/__tests__/unit/tick-methods/wilkinson-extended.spec.ts b/__tests__/unit/tick-methods/wilkinson-extended.spec.ts index 8b29c527..1adf04bd 100644 --- a/__tests__/unit/tick-methods/wilkinson-extended.spec.ts +++ b/__tests__/unit/tick-methods/wilkinson-extended.spec.ts @@ -29,10 +29,15 @@ describe('wilkinson-extended test', () => { expect(wilkinsonExtended(0, 0.1, 5)).toStrictEqual([0, 0.025, 0.05, 0.075, 0.1]); expect(wilkinsonExtended(0, 0.01, 5)).toStrictEqual([0, 0.0025, 0.005, 0.0075, 0.01]); expect(wilkinsonExtended(0, 0.001, 5)).toStrictEqual([0, 0.00025, 0.0005, 0.00075, 0.001]); - expect(wilkinsonExtended(0, 0.0001, 6)).toStrictEqual([0, 0.00002, 0.00004, 0.00006, 0.00008, 0.0001]); + expect(wilkinsonExtended(0, 0.0001, 6)).toStrictEqual([0, 0.00002, 0.00004, 0.00006, 0.00008, 0.0001, 0.00012]); expect(wilkinsonExtended(0, 0.00001, 6)).toStrictEqual([ 0, 0.000002, 0.000004, 0.000006, 0.000008, 0.00001, 0.000012, ]); expect(wilkinsonExtended(0, 0.000001, 6)).toStrictEqual([0, 0.0000002, 0.0000004, 0.0000006, 0.0000008, 0.000001]); + expect(wilkinsonExtended(0, 1e-15, 6)).toStrictEqual([0, 2e-16, 4e-16, 6e-16, 8e-16, 1e-15]); + }); + + test('precision', () => { + expect(wilkinsonExtended(0, 1.2, 5)).toStrictEqual([0, 0.3, 0.6, 0.9, 1.2]); }); }); diff --git a/__tests__/unit/utils/add.spec.ts b/__tests__/unit/utils/add.spec.ts deleted file mode 100644 index 1e8093c1..00000000 --- a/__tests__/unit/utils/add.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { precisionAdd as fn } from '../../../src/utils/precision-add'; - -describe('test precisionAdd', () => { - test('precisionAdd', () => { - expect(fn(0.1, 0.2)).toStrictEqual(0.3); - expect(fn(2.3, 2.4)).toStrictEqual(4.7); - expect(fn(-1.6, -1)).toStrictEqual(-2.6); - expect(fn(-2.0, 63)).toStrictEqual(61); - expect(fn(-3, 0.2)).toStrictEqual(-2.8); - expect(fn(1.3224e10, 1.3224e3)).toStrictEqual(13224001322.4); - expect(fn(1.6e-30, 1.6e-30)).toStrictEqual(3.2e-30); - }); -}); diff --git a/package.json b/package.json index f50cd692..1db7d96c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/scale", - "version": "0.4.1", + "version": "0.4.2", "description": "Toolkit for mapping abstract data into visual representation.", "license": "MIT", "main": "lib/index.js", diff --git a/src/tick-methods/wilkinson-extended.ts b/src/tick-methods/wilkinson-extended.ts index b200d1ba..50596581 100644 --- a/src/tick-methods/wilkinson-extended.ts +++ b/src/tick-methods/wilkinson-extended.ts @@ -1,6 +1,5 @@ import { indexOf, size } from '@antv/util'; import { TickMethod } from '../types'; -import { precisionAdd } from '../utils/precision-add'; export const DEFAULT_Q = [1, 5, 2, 2.5, 4, 3]; @@ -61,6 +60,11 @@ function legibility() { return 1; } +// 为了解决 js 运算的精度问题 +function pretty(n: number) { + return n < 1e-15 ? n : parseFloat(n.toFixed(15)); +} + /** * An Extension of Wilkinson's Algorithm for Position Tick Labels on Axes * https://www.yuque.com/preview/yuque/0/2019/pdf/185317/1546999150858-45c3b9c2-4e86-4223-bf1a-8a732e8195ed.pdf @@ -165,9 +169,10 @@ export const wilkinsonExtended: TickMethod = ( // 步长为浮点数时处理精度 const range = new Array(Math.floor(size)); - for (let tick = best.lmin; tick <= best.lmax; tick = precisionAdd(tick, best.lstep)) { - range[i] = tick; + for (let tick = best.lmin; tick <= best.lmax; tick += best.lstep) { + range[i] = pretty(tick); i += 1; } + return range; }; diff --git a/src/utils/precision-add.ts b/src/utils/precision-add.ts deleted file mode 100644 index 6ed31902..00000000 --- a/src/utils/precision-add.ts +++ /dev/null @@ -1,20 +0,0 @@ -function digitLength(num: number) { - // Get digit length of e - const eSplit = num.toString().split(/[eE]/); - const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0); - return len > 0 ? len : 0; -} - -/** - * 高精度加法,解决 0.1 + 0.2 !== 0.3 的经典问题 - * - * @param num1 加数 - * @param num2 被加数 - * @return {number} 返回值 - */ -export function precisionAdd(num1: number, num2: number) { - const num1Digits = digitLength(num1); - const num2Digits = digitLength(num2); - const baseNum = 10 ** Math.max(num1Digits, num2Digits); - return (num1 * baseNum + num2 * baseNum) / baseNum; -}