What is the maximum value of Nat64, Nat32, Nat16, Nat8, Int64, Int32, Int16, and Int8?
2^64-1, 2^32-1, 2^16-1, 2^8-1, 2^63-1, 2^31-1, 2^15-1, 2^7-1.
But note that there are very few reasons to use them. The main ones are algorithms requiring bit fiddling (e.g., crypto, compression), or matching an external interface or data structure using them. In almost all other cases you are better off with Nat or Int (safer, typically requiring less memory, often even faster).
Can you also tell me one more thing, what can be the maximum size of Trie or Hashmaps Data Structures ? Is there any limit ? or they just depend on size of Canister (limited upto 4gb?)
Oh, I didn’t know
Nat may require less memory AND be faster than
NatX… Why is that exactly?
Guess I need to refactor my code now.
They just depend on the size of the canister. But actually due to serialization, garbage collection, and other considerations, the available memory is probably closer to 3 GB, I believe. Hopefully that is temporary.
I noticed that you can’t use a Nat as a key in a TrieMap because the Hash.hash function seems to be limited to Nat32. Is there any way around that?
When I try to do it the error I get is “canister trapped explicitly, losing precision”
Use something like the following as your hash function(actually hard code the number for fewer cycles)
Also see: Hash Collisions
oh nice thanks, yeah I was going to use Text.hash but this solution seems better. I just hope we do get 64 bit hashes at some point.
That Hash.hash function is buggy and should be fixed (See issue Possible bug: Hash.hash(i : Nat) will trap if i >= 2^32 · Issue #345 · dfinity/motoko-base · GitHub)
You could use
/// Conversion. Wraps on overflow/underflow. Nat.fromIntWrap : Int -> Nat32;
Which won’t trap but won’t hash large numbers very well either (since it ignores all but the least significant 32 bits).
Note that you can apply
Nat.fromIntWrap(n) to a
n, by virtue of subtyping since
Nat <: Int.
I use @quint’s crypto library and Candy to get a 256 bit crypto secure hash like the below.
import Conversion "mo:candy/conversion"; import SHA256 "mo:crypto/SHA/SHA256"; SHA256.sum(CandyConversion.valuetoBytes(#Nat(a));
You may want to add a namespace into it depending on your use case. For that I use the .write() API endpoint.
let h = SHA256.New(); h.write(Conversion.valueToBytes(#Nat32(Text.hash("com.yourapp")))); h.write(Conversion.valueToBytes(#Nat(a); h.sum();
I had one issue with the crypto library where if I wrote a strange number of bytes it would throw. I think you have to have a mod(4) bytes…it would be nice if the crypto library had a padWriteLittleEndian() that would make sure a proper number of bytes get written.
[Oops, never clicked the button.]
Because Nat and Int are unboxed for small values (less than 31 bit), which means no allocation or indirection is required. The others are always stored with all bits, which means that Nat/Int32 and Nat/Int64 are always boxed on the heap.
import Debug "mo:base/Debug"; let max_int_64: Int = 9_223_372_036_854_775_807; // 2^63 - 1 Debug.print("max_int_64: " # debug_show(max_int_64)); Debug.print("max + 200 : " # debug_show(max_int_64 + 200));
max_int_64: +9_223_372_036_854_775_807 max + 200 : +9_223_372_036_854_776_007
Note that this same test with
let max_int_64: Int64 = 9_223_372_036_854_775_807; // 2^63 - 1 Debug.print("max_int_64: " # debug_show(max_int_64)); Debug.print("max + 200 : " # debug_show(max_int_64 + 200));
Produces an arithmetic overflow error (as expected).
Maybe this is the value I’m looking for?
You’ve moved beyond my knowledge…interested in the answer. I assumed that like nat, ints just keep growing and taking up space and there is a bit for + or -. Of course, you eventually run out of bits in your memory, but I didn’t think there was an actual limit.
@skilesare Just verified this, I start to receive
bigint function error errors when using any floats larger than 1.79e+308.
At least we can count all the atoms in the universe.
Int and Nat do not have any maximum value, other than what cannot be represented in 4 gigs of memory(*). However, 64 bit floats have, which is the one you have approximated. After that, everything get’s rounded to infinity. And trying to invert float infinity to Int will fail.
I thought the Motoko compiler would warn when a float literal is rounded to infinity, but perhaps I was mistaken.
(*) Though in practice, you will probably run out of cycles before you even get close.