summary refs log tree commit diff stats
path: root/compiler/saturate.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/saturate.nim')
-rw-r--r--compiler/saturate.nim79
1 files changed, 79 insertions, 0 deletions
diff --git a/compiler/saturate.nim b/compiler/saturate.nim
new file mode 100644
index 000000000..fe6e03c8b
--- /dev/null
+++ b/compiler/saturate.nim
@@ -0,0 +1,79 @@
+#
+#
+#           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(typeof(result))
+  else:
+    result = high(typeof(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(typeof(result))
+  else:
+    result = high(typeof(result))
+
+proc `|abs|`*(a: BiggestInt): BiggestInt =
+  if a != low(typeof(a)):
+    if a >= 0: result = a
+    else: result = -a
+  else:
+    result = low(typeof(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(typeof(a)) and b == -1'i64:
+    result = high(typeof(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(typeof(result))
+  else:
+    result = low(typeof(result))