-
Notifications
You must be signed in to change notification settings - Fork 31
Add toBytes proc #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add toBytes proc #128
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,7 +2,7 @@ | |||||||||||||||||||||||||||||||
## | ||||||||||||||||||||||||||||||||
## The bitwise operations behave as if negative numbers were represented in 2's complement. | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
import std/[algorithm, bitops, math, options] | ||||||||||||||||||||||||||||||||
import std/[algorithm, bitops, endians, math, options] | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
type | ||||||||||||||||||||||||||||||||
BigInt* = object | ||||||||||||||||||||||||||||||||
|
@@ -11,7 +11,7 @@ type | |||||||||||||||||||||||||||||||
# * if `a` is non-zero: `a.limbs[a.limbs.high] != 0` | ||||||||||||||||||||||||||||||||
# * if `a` is zero: `a.limbs.len <= 1` | ||||||||||||||||||||||||||||||||
limbs: seq[uint32] | ||||||||||||||||||||||||||||||||
isNegative: bool | ||||||||||||||||||||||||||||||||
isNegative*: bool | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
# forward declarations | ||||||||||||||||||||||||||||||||
|
@@ -78,7 +78,7 @@ const | |||||||||||||||||||||||||||||||
zero = initBigInt(0) | ||||||||||||||||||||||||||||||||
one = initBigInt(1) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
func isZero(a: BigInt): bool {.inline.} = | ||||||||||||||||||||||||||||||||
func isZero*(a: BigInt): bool {.inline.} = | ||||||||||||||||||||||||||||||||
a.limbs.len == 0 or (a.limbs.len == 1 and a.limbs[0] == 0) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
func abs*(a: BigInt): BigInt = | ||||||||||||||||||||||||||||||||
|
@@ -1309,3 +1309,76 @@ func powmod*(base, exponent, modulus: BigInt): BigInt = | |||||||||||||||||||||||||||||||
result = (result * basePow) mod modulus | ||||||||||||||||||||||||||||||||
basePow = (basePow * basePow) mod modulus | ||||||||||||||||||||||||||||||||
exponent = exponent shr 1 | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
proc toBytes*(a: BigInt; endianness = system.cpuEndian): seq[byte] = | ||||||||||||||||||||||||||||||||
## Convert a `BigInt` to a byte-sequence. | ||||||||||||||||||||||||||||||||
## The byte-sequence is the absolute (positive) value of `a`, it *does not* contain a sign-bit. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
let n = initBigInt("18591708106338011146") | ||||||||||||||||||||||||||||||||
let buf = n.toBytes(bigEndian) | ||||||||||||||||||||||||||||||||
doAssert buf == @[0x1'u8,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0xA] | ||||||||||||||||||||||||||||||||
if not a.isZero: | ||||||||||||||||||||||||||||||||
result = newSeq[byte](a.limbs.len shl 2) | ||||||||||||||||||||||||||||||||
var i: int | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nim initializes integers to zero. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know, but imo it's clearer to explicitly initialize them, rather than relying on implicit initialization. |
||||||||||||||||||||||||||||||||
case endianness | ||||||||||||||||||||||||||||||||
of bigEndian: | ||||||||||||||||||||||||||||||||
for s in [24, 16, 8, 0]: | ||||||||||||||||||||||||||||||||
result[i] = uint8(a.limbs[a.limbs.high] shr s) | ||||||||||||||||||||||||||||||||
if result[0] != 0x00: inc(i) | ||||||||||||||||||||||||||||||||
Comment on lines
+1325
to
+1327
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
for l in countdown(a.limbs.high.pred, a.limbs.low): | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A low on an array is always 0, a low on an empty seq can be -1. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already checked that |
||||||||||||||||||||||||||||||||
bigEndian32(addr result[i], unsafeAddr a.limbs[l]) | ||||||||||||||||||||||||||||||||
inc(i, 4) | ||||||||||||||||||||||||||||||||
result.setLen(i) | ||||||||||||||||||||||||||||||||
of littleEndian: | ||||||||||||||||||||||||||||||||
for l in 0..a.limbs.high: | ||||||||||||||||||||||||||||||||
littleEndian32(addr result[i], unsafeAddr a.limbs[l]) | ||||||||||||||||||||||||||||||||
inc(i, 4) | ||||||||||||||||||||||||||||||||
while result[pred i] == 0x00: | ||||||||||||||||||||||||||||||||
dec i | ||||||||||||||||||||||||||||||||
result.setLen(i) | ||||||||||||||||||||||||||||||||
Comment on lines
+1331
to
+1338
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
proc fromBytes*(result: var BigInt; buf: openarray[uint8]; endianness = system.cpuEndian) = | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This would be more ergonomic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer the var |
||||||||||||||||||||||||||||||||
## Convert a byte-sequence to `BigInt` value. | ||||||||||||||||||||||||||||||||
## The input `buf` is only interpreted as a natural (positive) number. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
var n: BigInt | ||||||||||||||||||||||||||||||||
n.fromBytes([0x1'u8,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0xA], bigEndian) | ||||||||||||||||||||||||||||||||
n = -n | ||||||||||||||||||||||||||||||||
doAssert n == initBigInt("-18591708106338011146") | ||||||||||||||||||||||||||||||||
Comment on lines
+1341
to
+1347
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
result.limbs.setLen((buf.len + 3) shr 2) | ||||||||||||||||||||||||||||||||
case endianness | ||||||||||||||||||||||||||||||||
of bigEndian: | ||||||||||||||||||||||||||||||||
var | ||||||||||||||||||||||||||||||||
li = result.limbs.high | ||||||||||||||||||||||||||||||||
bi = buf.low | ||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
var | ||||||||||||||||||||||||||||||||
limb: uint32 | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nim initializes uint32 to zero. |
||||||||||||||||||||||||||||||||
j = 4 - (buf.len and 3) | ||||||||||||||||||||||||||||||||
while j < 4: | ||||||||||||||||||||||||||||||||
limb = (limb shl 8) or buf[bi].uint32 | ||||||||||||||||||||||||||||||||
inc(bi) | ||||||||||||||||||||||||||||||||
inc(j) | ||||||||||||||||||||||||||||||||
Comment on lines
+1355
to
+1361
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, edited. |
||||||||||||||||||||||||||||||||
if bi > 0: | ||||||||||||||||||||||||||||||||
result.limbs[li] = limb | ||||||||||||||||||||||||||||||||
dec(li) | ||||||||||||||||||||||||||||||||
while li >= 0: | ||||||||||||||||||||||||||||||||
bigEndian32(addr result.limbs[li], unsafeAddr buf[bi]) | ||||||||||||||||||||||||||||||||
inc(bi, 4) | ||||||||||||||||||||||||||||||||
dec(li) | ||||||||||||||||||||||||||||||||
of littleEndian: | ||||||||||||||||||||||||||||||||
var | ||||||||||||||||||||||||||||||||
li = result.limbs.low | ||||||||||||||||||||||||||||||||
bi = buf.low | ||||||||||||||||||||||||||||||||
while (bi + 4) < buf.len: | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
littleEndian32(addr result.limbs[li], unsafeAddr buf[bi]) | ||||||||||||||||||||||||||||||||
inc(bi, 4) | ||||||||||||||||||||||||||||||||
inc(li) | ||||||||||||||||||||||||||||||||
if bi < buf.len: | ||||||||||||||||||||||||||||||||
var | ||||||||||||||||||||||||||||||||
limb: uint32 | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nim initializes uint32 to zero. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explicit is better than implicit. For integers, I may understand since we implicitly rely on the litteral 0 being an integer. |
||||||||||||||||||||||||||||||||
ji = buf.high | ||||||||||||||||||||||||||||||||
while ji >= bi: | ||||||||||||||||||||||||||||||||
limb = (limb shl 8) or buf[ji] | ||||||||||||||||||||||||||||||||
dec(ji) | ||||||||||||||||||||||||||||||||
result.limbs[li] = limb |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,7 +102,7 @@ proc main() = | |
when (NimMajor, NimMinor) >= (1, 5): | ||
block: # literals | ||
# workaround | ||
include tliterals | ||
include ./literals | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why rename this specific file and not the others? Since we overwrite the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok then. |
||
|
||
block: # zero | ||
# see https://github.com/nim-lang/bigints/issues/26 | ||
|
@@ -880,6 +880,22 @@ proc main() = | |
doAssert pred(a, 3) == initBigInt(4) | ||
doAssert succ(a, 3) == initBigInt(10) | ||
|
||
when nimvm: discard | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why doesn't this work in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Endianness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean |
||
else: | ||
let n = initBigInt("18591708106338011146") | ||
block: | ||
let buf = n.toBytes(bigEndian) | ||
doAssert buf == @[ 0x1'u8, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xA] | ||
var res: Bigint | ||
res.fromBytes(buf, bigEndian) | ||
doAssert res == n | ||
block: | ||
let buf = n.toBytes(littleEndian) | ||
doAssert buf == @[ 0xA'u8, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1 ] | ||
var res: Bigint | ||
res.fromBytes(buf, littleEndian) | ||
doAssert res == n | ||
|
||
|
||
static: main() | ||
main() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -20,3 +20,12 @@ block: # check uniformity | |||||
doAssert(trials/nbuckets*0.5 < float(x)) | ||||||
doAssert(float(x) < trials/nbuckets*1.5) | ||||||
|
||||||
block: # check serialization roundtrip | ||||||
const | ||||||
trials = 1024 | ||||||
var a, b: Bigint | ||||||
for x in 0..trials: | ||||||
a = rand(0.initBigInt..pow(2.initBigInt, x)) | ||||||
for endian in [bigEndian, littleEndian]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
b.fromBytes(a.toBytes(endian), endian) | ||||||
doAssert a == b |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.