3

How can I divide int64?

let v: int64 = 100
echo v / 10

Error Error: type mismatch: got <int64, int literal(10)>

Full example

import math

proc sec_to_min*(sec: int64): int = 
  let min = sec / 60 # <= error
  min.round.to_int

echo 100.sec_to_min

P.S.

And, is there a way to safely cast int64 to int, so the result would be int and not int64, with the check for overflow.

Alex Craft
  • 13,598
  • 11
  • 69
  • 133

2 Answers2

2

There has been already a bit of discussion over int64 division in this issue and probably some improvement to current state can be made. From the above issue:

  • a good reason for not having in stdlib float division between int64 is that it might it may incur in loss of precision and so the user should explicitly convertint64 to float
  • still, float division between int types is present in stdlib
  • on 64 bit system int is int64 (and so you have division between int64 in 64 bit systems)

For your use case I think the following (playground) should work (better to use div instead of doing float division and then rounding off):

import math

proc sec_to_min*(sec: int64): int = sec.int div 60

echo 100.sec_to_min

let a = high(int64)
echo a.int  # on playground this does not raise error since int is int64
echo a.int32  # this instead correctly raises error

output:

1
9223372036854775807
/usercode/in.nim(9)      in
/playground/nim/lib/system/fatal.nim(49) sysFatal
Error: unhandled exception: value out of range: 9223372036854775807 notin -2147483648 .. 2147483647 [RangeError]

P.S.: as you see above standard conversion has range checks

pietroppeter
  • 1,433
  • 13
  • 30
2

Apparently division between int64 types is terribly dangerous because it invokes an undying horde of bike shedding, but at least you can create your own operator:

proc `/`(x, y: int64): int64 = x div y

let v: int64 = 100
echo v / 10

Or

proc `/`(x, y: int64): int64 = x div y

import math

proc sec_to_min*(sec: int64): int = 
  int(sec / 60)

echo 100.sec_to_min

With regards to the int64 to int conversion, I'm not sure that makes much sense since most platforms will run int as an alias of int64. But of course you could be compiling/running on a 32 bit platform, where the loss would be tragic, so you can still do runtime checks:

let a = int64.high

echo "Unsurprising but potentially wrong ", int(a)

proc safe_int(big_int: int64): int =
  if big_int > int32.high:
    raise new_exception(Overflow_error, "Value is too high for 32 bit platforms")
  int(big_int)

echo "Reachable code ", safe_int(int32.high)
echo "Unreachable code ", safe_int(a)

Also, if you are running into confusing minute, hour, day conversions, you might want to look into distinct types to avoid adding months to seconds (or do so in a more safe way).

Grzegorz Adam Hankiewicz
  • 7,349
  • 1
  • 36
  • 78