Skip to content

Commit

Permalink
Fabo/fix rounding issue in small number (#2487)
Browse files Browse the repository at this point in the history
* fix rounding issue in small number

* added comment

* 'changelog'
  • Loading branch information
faboweb authored and jbibla committed Apr 25, 2019
1 parent 63ad4b6 commit 13dae41
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 139 deletions.
186 changes: 96 additions & 90 deletions app/src/renderer/scripts/num.js
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
}
1 change: 1 addition & 0 deletions changes/fao_fix-rounding
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
98 changes: 49 additions & 49 deletions test/unit/specs/scripts/num.spec.js
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`
})
})
})

0 comments on commit 13dae41

Please sign in to comment.