60 lines
2.2 KiB
Nim
60 lines
2.2 KiB
Nim
# Stint
|
|
# Copyright 2018 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
#
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
#
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
import ./datatypes, ./int_negabs, ./uint_div, ./int_comparison
|
|
|
|
# Here are the expected signs for division/modulo by opposite signs and both negative numbers
|
|
# in EVM
|
|
# Parity: https://github.com/paritytech/parity/blob/684322cd6f210684b890055c43d56bb1bc8cae15/ethcore/evm/src/interpreter/mod.rs#L729-L756
|
|
# - SDIV is sign(a) xor sign(b)
|
|
# - SMOD is sign(a)
|
|
# Go-Ethereum: https://github.com/ethereum/go-ethereum/blob/ba1030b6b84f810c04a82221a1b1c0a3dbf499a8/core/vm/instructions.go#L76-L104
|
|
# - SDIV is "if same sign, div(abs(a), abs(b)), else -div(abs(a), abs(b))
|
|
# - SMOD is "sign(a)"
|
|
#
|
|
# in Nim
|
|
# echo "10 div 3: " & $(10 div 3) # 3
|
|
# echo "10 mod 3: " & $(10 mod 3) # 1
|
|
# echo '\n'
|
|
# echo "10 div -3: " & $(10 div -3) # -3
|
|
# echo "10 mod -3: " & $(10 mod -3) # 1
|
|
# echo '\n'
|
|
# echo "-10 div 3: " & $(-10 div 3) # -3
|
|
# echo "-10 mod 3: " & $(-10 mod 3) # -1
|
|
# echo '\n'
|
|
# echo "-10 div -3: " & $(-10 div -3) # 3
|
|
# echo "-10 mod -3: " & $(-10 mod -3) # -1
|
|
# echo '\n'
|
|
|
|
func divmod*(x, y: SomeSignedInt): tuple[quot, rem: SomeSignedInt] {.inline.}=
|
|
# hopefully the compiler fuse that in a single op
|
|
(x div y, x mod y)
|
|
|
|
proc divmod*[T](x, y: IntImpl[T]): tuple[quot, rem: IntImpl[T]] =
|
|
## Divmod operation for multi-precision signed integer
|
|
|
|
result = cast[type result](divmod(
|
|
cast[UintImpl[T]](x.abs),
|
|
cast[UintImpl[T]](y.abs)
|
|
))
|
|
|
|
if (x.isNegative xor y.isNegative):
|
|
# If opposite signs
|
|
result.quot = -result.quot
|
|
if x.isNegative:
|
|
result.rem = -result.rem
|
|
|
|
func `div`*(x, y: IntImpl): IntImpl {.inline.} =
|
|
## Division operation for multi-precision signed integer
|
|
divmod(x,y).quot
|
|
|
|
func `mod`*(x, y: IntImpl): IntImpl {.inline.} =
|
|
## Division operation for multi-precision signed integer
|
|
divmod(x,y).rem
|