-
Notifications
You must be signed in to change notification settings - Fork 635
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Swaps: fix safe math negative number support, add comparison functions (
#5776) * Fix negative number support, add number comparison functions * Add Worklet suffix to safe math functions
- Loading branch information
1 parent
3bf7fae
commit 0889e09
Showing
2 changed files
with
270 additions
and
103 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,142 +1,221 @@ | ||
// Utility function to remove the decimal point and keep track of the number of decimal places | ||
const removeDecimal = (num: string): [bigint, number] => { | ||
const removeDecimalWorklet = (num: string): [bigint, number] => { | ||
'worklet'; | ||
const parts = num.split('.'); | ||
const decimalPlaces = parts.length === 2 ? parts[1].length : 0; | ||
const bigIntNum = BigInt(parts.join('')); | ||
return [bigIntNum, decimalPlaces]; | ||
}; | ||
|
||
const isNumberString = (value: string): boolean => { | ||
return /^\d+(\.\d+)?$/.test(value); | ||
const isNumberStringWorklet = (value: string): boolean => { | ||
'worklet'; | ||
return /^-?\d+(\.\d+)?$/.test(value); | ||
}; | ||
|
||
const isZero = (value: string): boolean => { | ||
const isZeroWorklet = (value: string): boolean => { | ||
'worklet'; | ||
if (parseFloat(value) === 0) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
|
||
// Utility function to scale the number up to 20 decimal places | ||
const scaleUp = (bigIntNum: bigint, decimalPlaces: number): bigint => { | ||
const scaleFactor = BigInt(10) ** (BigInt(20) - BigInt(decimalPlaces)); | ||
return bigIntNum * scaleFactor; | ||
const scaleUpWorklet = (bigIntNum: bigint, decimalPlaces: number): bigint => { | ||
'worklet'; | ||
const scaleFactor = BigInt(10) ** BigInt(20); | ||
return (bigIntNum * scaleFactor) / BigInt(10) ** BigInt(decimalPlaces); | ||
}; | ||
|
||
// Utility function to format the result with 20 decimal places and remove trailing zeros | ||
const formatResult = (result: bigint): string => { | ||
const resultStr = result.toString().padStart(21, '0'); // 20 decimal places + at least 1 integer place | ||
const formatResultWorklet = (result: bigint): string => { | ||
'worklet'; | ||
const isNegative = result < 0; | ||
const absResult = isNegative ? -result : result; | ||
const resultStr = absResult.toString().padStart(21, '0'); // 20 decimal places + at least 1 integer place | ||
const integerPart = resultStr.slice(0, -20) || '0'; | ||
let fractionalPart = resultStr.slice(-20); | ||
fractionalPart = fractionalPart.replace(/0+$/, ''); // Remove trailing zeros | ||
return fractionalPart.length > 0 ? `${integerPart}.${fractionalPart}` : integerPart; | ||
const formattedResult = fractionalPart.length > 0 ? `${integerPart}.${fractionalPart}` : integerPart; | ||
return isNegative ? `-${formattedResult}` : formattedResult; | ||
}; | ||
|
||
// Sum function | ||
export function sum(num1: string, num2: string): string { | ||
if (!isNumberString(num1) || !isNumberString(num2)) { | ||
export function sumWorklet(num1: string, num2: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
if (isZero(num1)) { | ||
if (isZeroWorklet(num1)) { | ||
return num2; | ||
} | ||
|
||
if (isZero(num2)) { | ||
if (isZeroWorklet(num2)) { | ||
return num1; | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimal(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimal(num2); | ||
const scaledBigInt1 = scaleUp(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUp(bigInt2, decimalPlaces2); | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
const result = scaledBigInt1 + scaledBigInt2; | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Subtract function | ||
export function sub(num1: string, num2: string): string { | ||
if (!isNumberString(num1) || !isNumberString(num2)) { | ||
export function subWorklet(num1: string, num2: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
|
||
if (isZero(num2)) { | ||
if (isZeroWorklet(num2)) { | ||
return num1; | ||
} | ||
|
||
const [bigInt1, decimalPlaces1] = removeDecimal(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimal(num2); | ||
const scaledBigInt1 = scaleUp(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUp(bigInt2, decimalPlaces2); | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
const result = scaledBigInt1 - scaledBigInt2; | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Multiply function | ||
export function mul(num1: string, num2: string): string { | ||
if (!isNumberString(num1) || !isNumberString(num2)) { | ||
export function mulWorklet(num1: string, num2: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
if (isZero(num1) || isZero(num2)) { | ||
if (isZeroWorklet(num1) || isZeroWorklet(num2)) { | ||
return '0'; | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimal(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimal(num2); | ||
const scaledBigInt1 = scaleUp(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUp(bigInt2, decimalPlaces2); | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
const result = (scaledBigInt1 * scaledBigInt2) / BigInt(10) ** BigInt(20); | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Divide function | ||
export function div(num1: string, num2: string): string { | ||
if (!isNumberString(num1) || !isNumberString(num2)) { | ||
export function divWorklet(num1: string, num2: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
if (isZero(num2)) { | ||
if (isZeroWorklet(num2)) { | ||
throw new Error('Division by zero'); | ||
} | ||
if (isZero(num1)) { | ||
if (isZeroWorklet(num1)) { | ||
return '0'; | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimal(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimal(num2); | ||
const scaledBigInt1 = scaleUp(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUp(bigInt2, decimalPlaces2); | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
const result = (scaledBigInt1 * BigInt(10) ** BigInt(20)) / scaledBigInt2; | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Modulus function | ||
export function mod(num1: string, num2: string): string { | ||
if (!isNumberString(num1) || !isNumberString(num2)) { | ||
export function modWorklet(num1: string, num2: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
if (isZero(num2)) { | ||
if (isZeroWorklet(num2)) { | ||
throw new Error('Division by zero'); | ||
} | ||
if (isZero(num1)) { | ||
if (isZeroWorklet(num1)) { | ||
return '0'; | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimal(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimal(num2); | ||
const scaledBigInt1 = scaleUp(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUp(bigInt2, decimalPlaces2); | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
const result = scaledBigInt1 % scaledBigInt2; | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Power function | ||
export function pow(base: string, exponent: string): string { | ||
if (!isNumberString(base) || !isNumberString(exponent)) { | ||
export function powWorklet(base: string, exponent: string): string { | ||
'worklet'; | ||
if (!isNumberStringWorklet(base) || !isNumberStringWorklet(exponent)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
if (isZero(base)) { | ||
if (isZeroWorklet(base)) { | ||
return '0'; | ||
} | ||
if (isZero(exponent)) { | ||
if (isZeroWorklet(exponent)) { | ||
return '1'; | ||
} | ||
const [bigIntBase, decimalPlaces] = removeDecimal(base); | ||
const scaledBigIntBase = scaleUp(bigIntBase, decimalPlaces); | ||
const [bigIntBase, decimalPlaces] = removeDecimalWorklet(base); | ||
const scaledBigIntBase = scaleUpWorklet(bigIntBase, decimalPlaces); | ||
const result = scaledBigIntBase ** BigInt(exponent) / BigInt(10) ** BigInt(20); | ||
return formatResult(result); | ||
return formatResultWorklet(result); | ||
} | ||
|
||
// Equality function | ||
export function equalWorklet(num1: string, num2: string): boolean { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
return scaledBigInt1 === scaledBigInt2; | ||
} | ||
|
||
// Greater than function | ||
export function greaterThanWorklet(num1: string, num2: string): boolean { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
return scaledBigInt1 > scaledBigInt2; | ||
} | ||
|
||
// Greater than or equal to function | ||
export function greaterThanOrEqualToWorklet(num1: string, num2: string): boolean { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
return scaledBigInt1 >= scaledBigInt2; | ||
} | ||
|
||
// Less than function | ||
export function lessThanWorklet(num1: string, num2: string): boolean { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
return scaledBigInt1 < scaledBigInt2; | ||
} | ||
|
||
// Less than or equal to function | ||
export function lessThanOrEqualToWorklet(num1: string, num2: string): boolean { | ||
'worklet'; | ||
if (!isNumberStringWorklet(num1) || !isNumberStringWorklet(num2)) { | ||
throw new Error('Arguments must be a numeric string'); | ||
} | ||
const [bigInt1, decimalPlaces1] = removeDecimalWorklet(num1); | ||
const [bigInt2, decimalPlaces2] = removeDecimalWorklet(num2); | ||
const scaledBigInt1 = scaleUpWorklet(bigInt1, decimalPlaces1); | ||
const scaledBigInt2 = scaleUpWorklet(bigInt2, decimalPlaces2); | ||
return scaledBigInt1 <= scaledBigInt2; | ||
} |
Oops, something went wrong.