Skip to content

Commit 74dcb0c

Browse files
committed
Add function to round numbers for 32-bit float storage
1 parent cae8c16 commit 74dcb0c

File tree

8 files changed

+21
-5
lines changed

8 files changed

+21
-5
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ const { ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
180180

181181
Note, that the performance is decreased with decimal rounding by about 20-25%, although if only 5% of your values are floating point, that will only have about a 1% impact overall.
182182

183+
In addition, msgpackr exports a `roundFloat32(number)` function that can be used to round floating point numbers to the maximum significant decimal digits that can be stored in 32-bit float, just as DECIMAL_ROUND does when encoding. This can be useful for determine how a number will be stored prior to encoding it.
184+
183185
## Performance
184186
Msgpackr is fast. Really fast. Here is comparison with the next fastest JS projects using the benchmark tool from `msgpack-lite` (and the sample data is from some clinical research data we use that has a good mix of different value types and structures). It also includes comparison to V8 native JSON functionality, and JavaScript Avro (`avsc`, a very optimized Avro implementation):
185187

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './pack.js'
2-
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource } from './unpack.js'
2+
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './unpack.js'
33
export { decodeIter, encodeIter } from './iterators.js'
44
export const useRecords = false
55
export const mapsAsObjects = true

node-index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './pack.js'
2-
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource} from './unpack.js'
2+
export { Unpackr, Decoder, C1, unpack, unpackMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './unpack.js'
33
export { PackrStream, UnpackrStream, PackrStream as EncoderStream, UnpackrStream as DecoderStream } from './stream.js'
44
export { decodeIter, encodeIter } from './iterators.js'
55
export const useRecords = false

pack.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ export class Packr extends Unpackr {
273273
targetView.setFloat32(position, value)
274274
let xShifted
275275
if (useFloat32 < 4 ||
276-
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
276+
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
277277
((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) {
278278
position += 4
279279
return

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "msgpackr",
33
"author": "Kris Zyp",
4-
"version": "1.4.3",
4+
"version": "1.4.4",
55
"description": "Ultra-fast MessagePack implementation with extensions for records and structured cloning",
66
"license": "MIT",
77
"types": "./index.d.ts",
@@ -47,7 +47,7 @@
4747
}
4848
},
4949
"optionalDependencies": {
50-
"msgpackr-extract": "^1.0.13"
50+
"msgpackr-extract": "^1.0.14"
5151
},
5252
"devDependencies": {
5353
"@rollup/plugin-json": "^4.1.0",

tests/test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var assert = chai.assert
1515
var Packr = msgpackr.Packr
1616
var unpack = msgpackr.unpack
1717
var unpackMultiple = msgpackr.unpackMultiple
18+
var roundFloat32 = msgpackr.roundFloat32
1819
var pack = msgpackr.pack
1920
var DECIMAL_FIT = msgpackr.FLOAT32_OPTIONS.DECIMAL_FIT
2021

@@ -531,6 +532,11 @@ suite('msgpackr basic tests', function(){
531532
assert.isTrue(deserialized.tooBig > 2n**65n)
532533
})
533534

535+
test('roundFloat32', function() {
536+
assert.equal(roundFloat32(0.00333000003), 0.00333)
537+
assert.equal(roundFloat32(43.29999999993), 43.3)
538+
})
539+
534540
test('buffers', function(){
535541
var data = {
536542
buffer1: new Uint8Array([2,3,4]),

unpack.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ export function unpackMultiple(messagePack: Buffer | Uint8Array, forEach?: (valu
4040
export function decode(messagePack: Buffer | Uint8Array): any
4141
export function addExtension(extension: Extension): void
4242
export function clearSource(): void
43+
export function roundFloat32(float32Number: number): number
4344
export const C1: {}

unpack.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,3 +964,10 @@ export const FLOAT32_OPTIONS = {
964964
DECIMAL_ROUND: 3,
965965
DECIMAL_FIT: 4
966966
}
967+
let f32Array = new Float32Array(1)
968+
let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
969+
export function roundFloat32(float32Number) {
970+
f32Array[0] = float32Number
971+
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
972+
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
973+
}

0 commit comments

Comments
 (0)