I’m trying to convert some numbers and I don’t get the results I would expect. I hope someone can explain to me, what I’m doing wrong and why I I don’t get the result I want.
My code looks like this:
And I receive this output:
18446744073709551615 # fits my expectation
18446744073709551615 # I would have expected 4294967295_u64
18446744073709551615 # I would have expected 255_u64
My (probably wrong) idea was:
-1_i8 would be equal to the bits
0000000000000000000000000000000000000000000000000000000000000000 | 11111111 should result in
255 in decimal representation).
Why isn’t it like that? I hopefully might avoid other mistakes once I understand why this didn’t work out.
What would be the best (as in primarily most performant, secondarily lowest code efforts) way to get the wanted results?
It works when I do
but I would prefer a more generic approach.
Thanks in advance!
Whenever there’s a math operation between two types, the result has the type of the left operand. The right operand is casted to the left operand’s type. At least that’s how we decided it should work in Crystal.
Yes, I figured that already out, and that’s fine.
But this doesn’t explain the unexpected result. Or maybe I’m just not seeing it (but this is still the same for the “working method” as well!?)
The type fits absolutely to my expectation. I’m surprised (and confused) by its value.
Okay - this is likely the explanation. I missed the upfront casting. Thanks.
Should anyone else want to do the same - this works for me:
x = self # needed to workaround #Error: can't take address of self
Um. That make no sense. What are you actually trying to achieve here?
p (-1_i64).foo # I want 18446744073709551615_u64
p (-1_i32).foo # I want 4294967295_u64
p (-1_i8).foo # I want 255_u64
And this works fine now.
Purpose/ intention is, to then do 7bit encoding on the UInt64 to send it over a socket, so a C# application, which expects the other side to send data via .Net’s BinaryWriter.Write7BitEncodedInt, can understand it. The stuff above was necessary for those cases when the value is negative.
And as this will now show up if someone searches for 7BitEncodedInt - here is the full method in case someone needs it:
def serialize7 (io)
x = self
(If someone is going to use it: be aware my use case requires only values up to 64bit - you might need more bits though and probably have to adjust the
The bitwise OR is not suitable for integer casts like this. Instead one could do:
# ditto for the rest of `Int::Signed`
def serialize7(io : IO, value : Int)
if value >= 0
while value > 0x7F
io.write_byte((value & 0x7F).to_u8! | 0x80_u8)
value >>= 7
serialize7(io, value.to_unsigned!) # size-preserving integer sign cast
# negative `BigInt`s go here
In fact I have had a need for
#to_unsigned! somewhere else in the standard library.
Didn’t get it the very first moment. But yes, this works. Thanks!
But it’s a lot more code, which needs to be adjusted for each type. My last solution fits all types, except the big ones, which I fortunately don’t need, so I’m probably go and stick with that (probably go rid of the u64, as I can’t remember any good reason I would have needed it for in the first place; but maybe there was and I just can’t remember it). Edit 2: went basically with your solution (it 's not much code, and it’s quickly done and won’t be touched again anyway, so yeah, why not)
You are referring to my very first approach when I started this topic, aren’t you? Yeah, I didn’t know that there is an automatic cast happening before the OR, but @asterite solved this part of my confusion already.
Anyway, thanks a lot