summary refs log tree commit diff stats
path: root/compiler/vmdeps.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-02-24 01:57:49 +0100
committerAraq <rumpf_a@web.de>2015-02-24 01:57:49 +0100
commit7324ed7f1fb5a265de57c95e08a5b4044c662d0e (patch)
treed3e18841463153e6d4bc9a8479891043126b116d /compiler/vmdeps.nim
parent752052e903c8f238a6e3a6f67ae36ee7e0943801 (diff)
downloadNim-7324ed7f1fb5a265de57c95e08a5b4
#
#
#           The Nim Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Saturated arithmetic routines. XXX Make part of the stdlib?

proc `|+|`*(a, b: BiggestInt): BiggestInt =
  ## saturated addition.
  result = a +% b
  if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
    return result
  if a < 0 or b < 0:
    result = low(result)
  else:
    result = high(result)

proc `|-|`*(a, b: BiggestInt): BiggestInt =
  result = a -% b
  if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
    return result
  if b > 0:
    result = low(result)
  else:
    result = high(result)

proc `|abs|`*(a: BiggestInt): BiggestInt =
  if a != low(a):
    if a >= 0: result = a
    else: result = -a
  else:
    result = low(a)

proc `|div|`*(a, b: BiggestInt): BiggestInt =
  # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
  if b == 0'i64:
    # make the same as ``div 1``:
    result = a
  elif a == low(a) and b == -1'i64:
    result = high(result)
  else:
    result = a div b

proc `|mod|`*(a, b: BiggestInt): BiggestInt =
  if b == 0'i64:
    result = a
  else:
    result = a mod b

proc `|*|`*(a, b: BiggestInt): BiggestInt =
  var
    resAsFloat, floatProd: float64
  result = a *% b
  floatProd = toBiggestFloat(a) # conversion
  floatProd = floatProd * toBiggestFloat(b)
  resAsFloat = toBiggestFloat(result)

  # Fast path for normal case: small multiplicands, and no info
  # is lost in either method.
  if resAsFloat == floatProd: return result

  # Somebody somewhere lost info. Close enough, or way off? Note
  # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
  # The difference either is or isn't significant compared to the
  # true value (of which floatProd is a good approximation).

  # abs(diff)/abs(prod) <= 1/32 iff
  #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
  if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
    return result

  if floatProd >= 0.0:
    result = high(result)
  else:
    result = low(result)