-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fabo/fix rounding issue in small number (#2487)
* fix rounding issue in small number * added comment * 'changelog'
- Loading branch information
Showing
3 changed files
with
146 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,96 @@ | ||
"use strict" | ||
import BigNumber from "bignumber.js" | ||
|
||
/** | ||
* Defines all numerical methods | ||
* @module num | ||
*/ | ||
|
||
export const SMALLEST = 1e-6 | ||
const language = window.navigator.userLanguage || window.navigator.language | ||
export function full(number = 0) { | ||
return new Intl.NumberFormat(language, { minimumFractionDigits: 6 }) | ||
.format(number) | ||
} | ||
export function shortNumber(number = 0) { | ||
return new Intl.NumberFormat(language, { minimumFractionDigits: 4 }).format(number) + `…` | ||
} | ||
export function pretty(number = 0) { | ||
return new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 2, maximumFractionDigits: 2 } | ||
).format(Math.round(number * 100) / 100) | ||
} | ||
// pretty print long decimals not in scientific notation | ||
export function prettyDecimals(number = 0) { | ||
let longDecimals = new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 20, maximumFractionDigits: 20 } | ||
).format(number) | ||
|
||
// remove all trailing zeros | ||
while (longDecimals.charAt(longDecimals.length - 1) === `0`) { | ||
longDecimals = longDecimals.substr(0, longDecimals.length - 1) | ||
} | ||
|
||
// remove decimal separator from whole numbers | ||
if (Number.isNaN(Number(longDecimals.charAt(longDecimals.length - 1)))) { | ||
longDecimals = longDecimals.substr(0, longDecimals.length - 1) | ||
} | ||
|
||
return longDecimals | ||
} | ||
export function prettyInt(number = 0) { | ||
return new Intl.NumberFormat(language).format(Math.round(number)) | ||
} | ||
export function percentInt(number = 0) { | ||
return new Intl.NumberFormat(language).format(Math.round(number * 100)) + `%` | ||
} | ||
export function percent(number = 0) { | ||
return new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 2, maximumFractionDigits: 2 } | ||
).format(Math.round(number * 10000) / 100) + `%` | ||
} | ||
export function atoms(number = 0) { | ||
return BigNumber(number).div(1e6).toNumber() | ||
} | ||
export function uatoms(number = 0) { | ||
return BigNumber(number).times(1e6).toString() | ||
} | ||
|
||
// convert micro denoms like uatom to display denoms like ATOM | ||
export function viewDenom(denom) { | ||
if (denom.charAt(0) === `u`) { | ||
return denom.substr(1).toUpperCase() | ||
} | ||
return denom.toUpperCase() | ||
} | ||
|
||
export function viewCoin({ amount, denom }) { | ||
return { | ||
amount: full(atoms(amount)), | ||
denom: viewDenom(denom) | ||
} | ||
} | ||
|
||
export default { | ||
SMALLEST, | ||
atoms, | ||
uatoms, | ||
viewDenom, | ||
viewCoin, | ||
full, | ||
shortNumber, | ||
pretty, | ||
prettyInt, | ||
percent, | ||
percentInt, | ||
prettyDecimals | ||
} | ||
"use strict" | ||
import BigNumber from "bignumber.js" | ||
|
||
/** | ||
* Defines all numerical methods | ||
* @module num | ||
*/ | ||
|
||
// truncate decimals to not round when using Intl.NumberFormat | ||
function truncate(number, digits) { | ||
return Math.trunc(number * Math.pow(10, digits)) / Math.pow(10, digits) | ||
} | ||
|
||
export const SMALLEST = 1e-6 | ||
const language = window.navigator.userLanguage || window.navigator.language | ||
export function full(number = 0) { | ||
return new Intl.NumberFormat(language, { minimumFractionDigits: 6 }) | ||
.format(truncate(number, 6)) | ||
} | ||
export function shortNumber(number = 0) { | ||
return new Intl.NumberFormat(language, { minimumFractionDigits: 4 }) | ||
.format(truncate(number, 4)) + `…` | ||
} | ||
export function pretty(number = 0) { | ||
return new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 2, maximumFractionDigits: 2 } | ||
).format(Math.round(number * 100) / 100) | ||
} | ||
// pretty print long decimals not in scientific notation | ||
export function prettyDecimals(number = 0) { | ||
let longDecimals = new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 20, maximumFractionDigits: 20 } | ||
).format(number) | ||
|
||
// remove all trailing zeros | ||
while (longDecimals.charAt(longDecimals.length - 1) === `0`) { | ||
longDecimals = longDecimals.substr(0, longDecimals.length - 1) | ||
} | ||
|
||
// remove decimal separator from whole numbers | ||
if (Number.isNaN(Number(longDecimals.charAt(longDecimals.length - 1)))) { | ||
longDecimals = longDecimals.substr(0, longDecimals.length - 1) | ||
} | ||
|
||
return longDecimals | ||
} | ||
export function prettyInt(number = 0) { | ||
return new Intl.NumberFormat(language).format(Math.round(number)) | ||
} | ||
export function percentInt(number = 0) { | ||
return new Intl.NumberFormat(language).format(Math.round(number * 100)) + `%` | ||
} | ||
export function percent(number = 0) { | ||
return new Intl.NumberFormat( | ||
language, | ||
{ minimumFractionDigits: 2, maximumFractionDigits: 2 } | ||
).format(Math.round(number * 10000) / 100) + `%` | ||
} | ||
export function atoms(number = 0) { | ||
return BigNumber(number).div(1e6).toNumber() | ||
} | ||
export function uatoms(number = 0) { | ||
return BigNumber(number).times(1e6).toString() | ||
} | ||
|
||
// convert micro denoms like uatom to display denoms like ATOM | ||
export function viewDenom(denom) { | ||
if (denom.charAt(0) === `u`) { | ||
return denom.substr(1).toUpperCase() | ||
} | ||
return denom.toUpperCase() | ||
} | ||
|
||
export function viewCoin({ amount, denom }) { | ||
return { | ||
amount: full(atoms(amount)), | ||
denom: viewDenom(denom) | ||
} | ||
} | ||
|
||
export default { | ||
SMALLEST, | ||
atoms, | ||
uatoms, | ||
viewDenom, | ||
viewCoin, | ||
full, | ||
shortNumber, | ||
pretty, | ||
prettyInt, | ||
percent, | ||
percentInt, | ||
prettyDecimals | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[Fixed] [#2487](https://github.com/cosmos/lunie/pull/2487) Remove rounding in small numbers @faboweb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,49 @@ | ||
import num from "renderer/scripts/num" | ||
|
||
describe(`number helper`, () => { | ||
it(`should format numbers showing many decimals`, () => { | ||
expect(num.full(1001950.123456)).toBe(`1,001,950.123456`) | ||
}) | ||
|
||
it(`should format numbers showing many decimals`, () => { | ||
expect(num.shortNumber(1.123456789)).toBe(`1.1235…`) | ||
}) | ||
|
||
it(`should format numbers showing few decimals`, () => { | ||
expect(num.pretty(1001950.123456)).toBe(`1,001,950.12`) | ||
}) | ||
|
||
it(`should format numbers showing no decimals`, () => { | ||
expect(num.prettyInt(1001950.123456)).toBe(`1,001,950`) | ||
}) | ||
|
||
it(`should format percent without decimals`, () => { | ||
expect(num.percentInt(0.2612)).toBe(`26%`) | ||
}) | ||
|
||
it(`should format percent with decimals`, () => { | ||
expect(num.percent(0.2612)).toBe(`26.12%`) | ||
}) | ||
|
||
it(`should format long decimals well`, () => { | ||
expect(num.prettyDecimals(1e-8)).toBe(`0.00000001`) | ||
}) | ||
|
||
it(`should format long decimals well if whole number`, () => { | ||
expect(num.prettyDecimals(12)).toBe(`12`) | ||
}) | ||
|
||
it(`should convert utam denom to atom denom`, () => { | ||
expect(num.viewDenom(`uatom`)).toBe(`ATOM`) | ||
}) | ||
|
||
it(`should convert SDK coins to view coins`, () => { | ||
expect(num.viewCoin({ | ||
denom: `uatom`, | ||
amount: 1000000 | ||
})).toEqual({ | ||
denom: `ATOM`, | ||
amount: `1.000000` | ||
}) | ||
}) | ||
}) | ||
import num from "renderer/scripts/num" | ||
|
||
describe(`number helper`, () => { | ||
it(`should format numbers showing many decimals`, () => { | ||
expect(num.full(1001950.123456)).toBe(`1,001,950.123456`) | ||
}) | ||
|
||
it(`should format numbers showing many decimals`, () => { | ||
expect(num.shortNumber(1.123456789)).toBe(`1.1234…`) | ||
}) | ||
|
||
it(`should format numbers showing few decimals`, () => { | ||
expect(num.pretty(1001950.123456)).toBe(`1,001,950.12`) | ||
}) | ||
|
||
it(`should format numbers showing no decimals`, () => { | ||
expect(num.prettyInt(1001950.123456)).toBe(`1,001,950`) | ||
}) | ||
|
||
it(`should format percent without decimals`, () => { | ||
expect(num.percentInt(0.2612)).toBe(`26%`) | ||
}) | ||
|
||
it(`should format percent with decimals`, () => { | ||
expect(num.percent(0.2612)).toBe(`26.12%`) | ||
}) | ||
|
||
it(`should format long decimals well`, () => { | ||
expect(num.prettyDecimals(1e-8)).toBe(`0.00000001`) | ||
}) | ||
|
||
it(`should format long decimals well if whole number`, () => { | ||
expect(num.prettyDecimals(12)).toBe(`12`) | ||
}) | ||
|
||
it(`should convert utam denom to atom denom`, () => { | ||
expect(num.viewDenom(`uatom`)).toBe(`ATOM`) | ||
}) | ||
|
||
it(`should convert SDK coins to view coins`, () => { | ||
expect(num.viewCoin({ | ||
denom: `uatom`, | ||
amount: 1000000 | ||
})).toEqual({ | ||
denom: `ATOM`, | ||
amount: `1.000000` | ||
}) | ||
}) | ||
}) |