Skip to content

Commit

Permalink
Add full floating point support with divFloat function
Browse files Browse the repository at this point in the history
  • Loading branch information
paullinator committed Dec 5, 2023
1 parent 2f6deff commit 03779b7
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 13 deletions.
36 changes: 36 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/src/index.js",
"preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": [
"${workspaceFolder}/lib/**/*.js"
]
},
{
"type": "node",
"request": "launch",
"name": "Mocha Tests",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"-r",
"sucrase/register",
"${workspaceFolder}/test/**/*.test.ts",
],
"internalConsoleOptions": "openOnSessionStart",
"skipFiles": [
"<node_internals>/**"
]
},
]
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- added: divf() to do floating point division with no need to specify precision

## 4.2.0 (2023-12-05)

- added: New toBns function to convert JS number to big number strings
Expand Down
46 changes: 33 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import BN from 'bn.js'

interface ShiftPair {
shift: number
extraShift: number
x: string
y: string
}

const SCI_NOTATION_REGEX = /^(-?\d*\.?\d*)e((?:\+|-)?\d+)$/

const RECOMMENDED_DIVIDE_DIGITS = 77
// -----------------------------------------------------------------------------
// Public
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -70,25 +71,36 @@ export function sub(
return base === 10 ? out : out.replace(/^(-)?/, '$10x')
}

export function divf(x1: string, y1: string): string {
return div(x1, y1, true)
}

export function div(
x1: string | number,
y1: string | number,
precision: number = 0,
precision: true | number = 0,
base: number = 10
): string {
if (base !== 10 && precision > 0) {
if (base !== 10 && precision !== 0) {
throw new Error('Cannot operate on floating point hex values')
}
if (base !== 10 && base !== 16) throw new Error('Unsupported base')
let { x, y } = floatShifts(x1, y1, precision)
let { x, y, extraShift } = floatShifts(
x1,
y1,
precision === true || precision > 0
)
const xBase = isHex(x) ? 16 : 10
const yBase = isHex(y) ? 16 : 10
x = cropHex(x)
y = cropHex(y)
const xBN = new BN(x, xBase)
const yBN = new BN(y, yBase)
let out = xBN.div(yBN).toString(base)
out = addDecimal(out, precision)
out = addDecimal(out, extraShift)
if (typeof precision === 'number' && precision > 0) {
out = toFixed(out, 0, precision)
}
return base === 10 ? out : out.replace(/^(-)?/, '$10x')
}

Expand Down Expand Up @@ -323,10 +335,11 @@ function cropHex(x: string): string {
function floatShifts(
xStart: string | number,
yStart: string | number,
moreShift?: number
doFloat: boolean = false
): ShiftPair {
let x = toBns(xStart)
let y = toBns(yStart)

let xPos: number = x.indexOf('.')
let yPos: number = y.indexOf('.')

Expand All @@ -345,7 +358,7 @@ function floatShifts(
yPos = y.indexOf('.')
}

if (xPos !== -1 || yPos !== -1 || typeof moreShift === 'number') {
if (xPos !== -1 || yPos !== -1 || doFloat) {
if (xHex || yHex) {
throw new Error('Cannot operate on base16 float values')
}
Expand All @@ -362,15 +375,21 @@ function floatShifts(
}

const shift = xShift > yShift ? xShift : yShift
let moreS = 0
if (typeof moreShift === 'number') {
moreS = moreShift
}

x = addZeros(x.replace('.', ''), shift + moreS - xShift)
x = addZeros(x.replace('.', ''), shift - xShift)
y = addZeros(y.replace('.', ''), shift - yShift)

const out: ShiftPair = { x, y, shift }
let extraShift = 0
if (doFloat) {
const totalLength = x.length + y.length
extraShift =
totalLength > RECOMMENDED_DIVIDE_DIGITS
? totalLength
: RECOMMENDED_DIVIDE_DIGITS
x = addZeros(x, extraShift)
}

const out: ShiftPair = { x, y, shift, extraShift }

return out
} else {
Expand All @@ -379,6 +398,7 @@ function floatShifts(
x,
y,
shift: 0,
extraShift: 0,
}
return out
}
Expand Down
56 changes: 56 additions & 0 deletions test/biggystring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
add,
ceil,
div,
divf,
eq,
floor,
gt,
Expand Down Expand Up @@ -173,6 +174,61 @@ describe('div', function () {
'400000000000000000000000000'
)
})
it('divf with smaller numerator', function () {
assert.equal(
divf('258314', '44259003611849456'),
'0.00000000000583641697552453787845483515333625998899100236535579470378814823369'
)
})
it('divf with smaller denominator', function () {
assert.equal(
divf('44259003611849456', '258314'),
'171337997986.36332525530942960892557120403849578420062404670285001974341305542866433875051'
)
})
it('divf with decimal numerator', function () {
assert.equal(
divf('4425900361184.9456', '258314'),
'17133799.79863633252553094296089255712040384957842006240467028500197434130554286643387'
)
})
it('divf with decimal denominator', function () {
assert.equal(
divf('258314', '4425900361184.9456'),
'0.00000005836416975524537878454835153336259988991002365355794703788148233694743'
)
})
it('divf with <1 decimal numerator', function () {
assert.equal(
divf('0.00001234', '258314'),
'0.00000000004777131707921367018434928033323784231594106397640081451256997297862'
)
})
it('divf with <1 decimal denominator', function () {
assert.equal(
divf('258314', '0.00001234'),
'20933063209.07617504051863857374392220421393841166936790923824959481361426256077795786061'
)
})
it('divf with very big divided by very small', function () {
assert.equal(
divf(
'258314184762834762387462843985739845739845734.123876328756',
'0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234'
),
'209330781817532222356128722840956114862111615983692324761750405186385737439222042139384116693679092382495948136142625607779578606158833063209.0761750405186385737439222042139384116693679092382495948136142625607779578606158833063209076175040518638573743922204213938411669367909238249594813614262560777957860615883306320907617504051863857374392220421393841166936790923824959481361426256077'
)
})
it('divf with very small divided by very big', function () {
assert.equal(
divf(
'0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234',
'258314184762834762387462843985739845739845734.123876328756'
),
'0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047771282910110753934911288073993261089606462593095155090550880308370686890364229227812023898933169363535'
)
})

it('very big float (precision 9, base 10)', function () {
assert.equal(
div('800000000000000000000000000.000000008', '2', 9, 10),
Expand Down

0 comments on commit 03779b7

Please sign in to comment.