Skip to content

Commit

Permalink
fix: calcPercentage div by zero
Browse files Browse the repository at this point in the history
  • Loading branch information
itsmnthn committed Mar 23, 2024
1 parent 141bd9f commit 9afaa55
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 15 deletions.
6 changes: 4 additions & 2 deletions packages/utils/src/units/bigUtils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const ZERO = BigInt(0)

/**
* Gets the sign of a number represented as a string, or bigint.
* @param num {string | bigint} The number in string or bigint format to be used for deciding the sign.
* @returns 0 if num is zero, 1 if num is positive, -1 if num is negative.
*/
export function getBigSign(num: string | bigint): -1 | 0 | 1 {
num = BigInt(num)
return num === BigInt(0) ? 0 : num > BigInt(0) ? 1 : -1
return num === ZERO ? 0 : num > ZERO ? 1 : -1
}

/**
Expand All @@ -16,5 +18,5 @@ export function getBigSign(num: string | bigint): -1 | 0 | 1 {
*/
export function absBig(num: bigint | string): bigint {
num = BigInt(num)
return num < BigInt(0) ? -num : num
return num < ZERO ? -num : num
}
3 changes: 3 additions & 0 deletions packages/utils/src/units/formatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ test('adds comma to a number or amount string', () => {
expect(formatWithComma('235')).toMatchInlineSnapshot('"235"')
expect(formatWithComma('0.235')).toMatchInlineSnapshot('"0.235"')
expect(formatWithComma('.23512142')).toMatchInlineSnapshot('".23512142"')
expect(formatWithComma('< 0.009')).toMatchInlineSnapshot('"< 0.009"')
expect(formatWithComma('> 0.001')).toMatchInlineSnapshot('"> 0.001"')
expect(formatWithComma('> -0.001')).toMatchInlineSnapshot('"> -0.001"')
})

test('un-scales the given amount to display value and formatted with preserved decimals', () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/utils/src/units/multiple.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { absBig } from './bigUtils'

const ZERO = BigInt(0)

/**
* Checks if the given value is a multiple of the specified minimum value.
* Both the value and the minimum should be represented as strings to maintain precision
Expand All @@ -17,9 +19,8 @@ export function isMultipleOfMinimum(value: string | bigint, minimum: string | bi
// (x != 0 && x % y == 0)
value = absBig(value)
minimum = absBig(minimum)
const zero = BigInt(0)

return value !== zero && minimum !== zero && value % minimum === zero && value >= minimum
return value !== ZERO && minimum !== ZERO && value % minimum === ZERO && value >= minimum
}

/**
Expand All @@ -40,14 +41,13 @@ export function reduceByRemainder(value: string | bigint, minimum: string | bigi
// Convert strings to BigInt for calculation
value = BigInt(value)
minimum = BigInt(minimum)
const zero = BigInt(0)

if (value === zero || minimum === zero)
return zero
if (value === ZERO || minimum === ZERO)
return ZERO

// Check if value is already a multiple of minimum
const remainder = value % minimum
if (remainder === zero)
if (remainder === ZERO)
return value

return value - remainder
Expand Down
11 changes: 11 additions & 0 deletions packages/utils/src/units/percent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ test('calc percent of the given value', () => {
expect(calcPercentValue(1e6, 0, 6)).toMatchInlineSnapshot('0n')
expect(calcPercentValue(50, 150, 0)).toMatchInlineSnapshot('75n')
expect(calcPercentValue(50, 1500000000000000, 0)).toMatchInlineSnapshot('750000000000000n')
expect(calcPercentValue(0, 0, 0)).toMatchInlineSnapshot('0n')
expect(calcPercentValue(0, 100, 0)).toMatchInlineSnapshot('0n')
})

test('calc percentage of the second value from the main value', () => {
Expand All @@ -29,18 +31,27 @@ test('calc percentage of the second value from the main value', () => {
expect(calcPercentage(50, 75, 0)).toMatchInlineSnapshot('150')
expect(calcPercentage(50, 750, 0)).toMatchInlineSnapshot('1500')
expect(calcPercentage(1e6, 0, 6)).toMatchInlineSnapshot('0')
expect(calcPercentage(0, 0, 6)).toMatchInlineSnapshot('0')
expect(calcPercentage(0, 100, 6)).toMatchInlineSnapshot('0')
})

test('increase a number by given percentage', () => {
expect(increaseByPercentage('100', 10, 2)).toMatchInlineSnapshot('110n')
expect(increaseByPercentage('100', 25, 2)).toMatchInlineSnapshot('125n')
expect(increaseByPercentage('100', 0, 2)).toMatchInlineSnapshot('100n')
expect(increaseByPercentage('100', 0, 2)).toMatchInlineSnapshot('100n')
expect(increaseByPercentage(-100, 50, 9)).toMatchInlineSnapshot('-50n')
expect(increaseByPercentage(0, 50, 9)).toMatchInlineSnapshot('0n')
expect(increaseByPercentage(0, 0, 9)).toMatchInlineSnapshot('0n')
expect(increaseByPercentage(-0, 0, 9)).toMatchInlineSnapshot('0n')
})

test('decease a number by given percentage', () => {
expect(decreaseByPercentage('100', 10, 2)).toMatchInlineSnapshot('90n')
expect(decreaseByPercentage('100', 25, 2)).toMatchInlineSnapshot('75n')
expect(decreaseByPercentage('100', 0, 2)).toMatchInlineSnapshot('100n')
expect(decreaseByPercentage(-100, 50, 9)).toMatchInlineSnapshot('-150n')
expect(decreaseByPercentage(0, 50, 9)).toMatchInlineSnapshot('0n')
expect(decreaseByPercentage(0, 0, 9)).toMatchInlineSnapshot('0n')
expect(decreaseByPercentage(-0, 0, 9)).toMatchInlineSnapshot('0n')
})
23 changes: 16 additions & 7 deletions packages/utils/src/units/percent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { scale } from './scale'
import { unScale, unScaleToBase } from './unscale'

const ZERO = BigInt(0)

/**
* Calculates the specified percentage of a given value.
*
Expand Down Expand Up @@ -49,16 +51,23 @@ const percentCatalyst = 6
export function calcPercentage(
value: string | number | bigint, secondValue: string | number | bigint, decimals: number, precision = 3,
) {
return Number(Number(unScale(
scale(BigInt(secondValue), decimals + decimals + percentCatalyst) / BigInt(value),
decimals + decimals + percentCatalyst - 2,
)).toFixed(precision))
value = BigInt(value)
secondValue = BigInt(secondValue)
if (secondValue === ZERO || value === ZERO)
return 0

return Number(
Number(unScale(
scale(secondValue, decimals + decimals + percentCatalyst) / value,
decimals + decimals + percentCatalyst - 2,
)).toFixed(precision),
)
}

/**
* Increase a number by given percentage
*
* @param value - The number to increase
* @param value - The number to increasea
* @param percentage - The percentage to increase by
* @param decimals - The decimals of the value.
*
Expand All @@ -71,7 +80,7 @@ export function calcPercentage(
*/
export function increaseByPercentage(value: string | bigint | number, percentage: number | string, decimals: number) {
value = BigInt(value)
return value + (calcPercentValue(value, percentage, decimals) * (value < BigInt(0) ? BigInt(-1) : BigInt(1)))
return value + (calcPercentValue(value, percentage, decimals) * (value < ZERO ? BigInt(-1) : BigInt(1)))
}

/**
Expand All @@ -90,5 +99,5 @@ export function increaseByPercentage(value: string | bigint | number, percentage
*/
export function decreaseByPercentage(value: string | bigint | number, percentage: number | string, decimals: number) {
value = BigInt(value)
return value - (calcPercentValue(value, percentage, decimals) * (value < BigInt(0) ? BigInt(-1) : BigInt(1)))
return value - (calcPercentValue(value, percentage, decimals) * (value < ZERO ? BigInt(-1) : BigInt(1)))
}

0 comments on commit 9afaa55

Please sign in to comment.