Skip to content
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

Type conversion for small BigInts into integers #72

Closed
dlesnoff opened this issue Jan 9, 2022 · 7 comments
Closed

Type conversion for small BigInts into integers #72

dlesnoff opened this issue Jan 9, 2022 · 7 comments

Comments

@dlesnoff
Copy link
Contributor

dlesnoff commented Jan 9, 2022

Since BigInt's limb parameter has become private, thus we can not easily cast BigInts with absolute value less than 2^32 to an int or even a uint32.
The only workaround yet is to use the keyword cast[int]. But this does not always do what we want.
To get only the smallest limb, we also have to define a mask like 2^32 - 1 and to apply an ineffective and.
Can we implement some functions like … ?:

  • toUint32(a: BigInt): uint32 returns the only limb for BigInts between 1-2^32 and +2^32-1 (small BigInts).
  • toInt(a: BigInt): int cast the BigInt if it is small enough, into an int, according to the sign of BigInt, with correct representation (2's complement) and raises a ValueError if the cast can not be done (if int is stored on 32 bits, it may not fit if the heavy weight bit of the uint32 corresponding to first limb is 1).
  • toUint64(a: BigInt): uint64 returns the uint64 made up of one to two limbs, if the BigInt is small enough.
  • toFloat like described in the similar issue Feature request: toBiggestInt #34.
@konsumlamm
Copy link
Contributor

konsumlamm commented Jan 10, 2022

The only workaround yet is to use the keyword cast[int]. But this does not always do what we want.

That never does what you want. I suggest you read the documentation for cast, it merely reinterprets the underlying bits.

I generally agree that functions to convert a BigInt to some integer types are useful, but how should we handle the case of the BigInt being out of range? I see several possibilities:

  • raise an exception
  • return an Option
  • return the lowest/highest value (especially for floats, where we have Inf/-Inf)
  • cut off the higher bits (i.e. return x mod 2^n where n is the number of bits of the resut)

EDIT: Added a 4th option.

@narimiran
Copy link
Member

@Araq: you might be interested in this discussion, i.e. give your opinion on how to best proceed with this.

@dlesnoff
Copy link
Contributor Author

We can not return the lowest/highest value for type conversions to integers as a BigInt can be any value that an int can contain.
The first solution forces the user to wrap any potentially dangerous cast in a try .. except .. finally clause.
I have not used Option in my programs yet, if I understand the user will have to check (everytime ?) whether the Option contains a value ?

@Araq
Copy link
Member

Araq commented Jan 10, 2022

IMO the prototype should be:

proc toFixedInt*[T](b: BigInt): Option[T]

with the hopefully obvious semantics.

@Araq Araq closed this as completed in 48b0b25 Jan 15, 2022
Araq added a commit that referenced this issue Jan 15, 2022
@konsumlamm
Copy link
Contributor

This issue should be reopened, toSignedInt only provides conversion to signed integers. I'd also argue that it should be renamed to toInt and also support unsigned integers (rather than adding a new toUnsignedInt function).

@narimiran narimiran reopened this Jan 16, 2022
@Araq
Copy link
Member

Araq commented Jan 16, 2022

I also really need pred and succ. Implementation can be as simple as:

proc pred*(a: BigInt; def = 1): BigInt =
  a - initBigInt(def)

proc succ*(a: BigInt; def = 1): BigInt =
  a + initBigInt(def)

@konsumlamm
Copy link
Contributor

This has been addressed in #100.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants