Comment diviser int64 dans Nim?

Sep 17 2020

Comment puis-je diviser int64?

let v: int64 = 100
echo v / 10

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

Exemple complet

import math

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

echo 100.sec_to_min

PS

Et, est - il un moyen de jeter en toute sécurité int64à int, de sorte que le résultat serait intet non int64, avec le chèque de trop - plein.

Réponses

2 pietroppeter Sep 17 2020 at 17:26

Il y a déjà eu un peu de discussion sur la int64division dans cette question et probablement une certaine amélioration de l'état actuel peut être apportée. Du problème ci-dessus:

  • une bonne raison pour ne pas avoir de division flottante dans stdlib int64est que cela pourrait entraîner une perte de précision et que l'utilisateur devrait donc explicitement convertir int64enfloat
  • encore, la floatdivision entre les inttypes est présente dans stdlib
  • sur un système 64 bits int est int64 (et vous avez donc une division entre int64 dans les systèmes 64 bits)

Pour votre cas d'utilisation, je pense que ce qui suit ( terrain de jeu ) devrait fonctionner (mieux vaut utiliser div au lieu de faire une division flottante puis d'arrondir):

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

production:

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]

PS: comme vous le voyez ci-dessus, la conversion standard a des contrôles de plage

1 GrzegorzAdamHankiewicz Sep 17 2020 at 17:57

Apparemment, la division entre les types int64 est terriblement dangereuse car elle invoque une horde éternelle de perte de vélos, mais au moins vous pouvez créer votre propre opérateur:

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

let v: int64 = 100
echo v / 10

Ou

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

En ce qui concerne la conversion en int64to int, je ne suis pas sûr que cela ait beaucoup de sens, car la plupart des plates-formes fonctionneront intcomme un alias de int64. Mais bien sûr, vous pourriez compiler / exécuter sur une plate-forme 32 bits, où la perte serait tragique, vous pouvez donc toujours faire des vérifications à l'exécution:

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)

De plus, si vous rencontrez des conversions confuses en minutes, heures, jours, vous voudrez peut-être examiner différents types pour éviter d'ajouter des mois à des secondes (ou le faire de manière plus sûre).