
# floatTests.py

import math, sys
from floatUtils import *


# -------- main ---------------

print("\int info:", sys.int_info)
print()
i = sys.maxsize
print("int max: ", i)   # 9223372036854775807
print("increment error? ", i == i + 1)   # False
i += 1
print("Incremented:", i)   # 9223372036854775808

print("\nFloat info:", sys.float_info)
print()
f = sys.float_info.max
print("float max: ", f)   # 1.7976931348623157e+308
print("Increment error? ", f == f + 1)  # True
f += 1
print("Incremented:", f) # 1.7976931348623157e+308

print()
f = sys.float_info.max
v = 0
while True:
  try:
    f = f*(10**v)
    print(v, f)
    if math.isinf(f):
      print("detected infinity")
      break
    v += 1
  except Exception as e:
    print("Exception:", e)
    break

print()
v = 2
while True: 
  print(f"exp({v}): ", end='')
  try:
    print(math.exp(v))
  except Exception as e:
    print(type(e).__name__, e.args)  # was e
    break
  v *= 2

print()
f = sys.float_info.min
print("float min: ", f)

while f != 0:
  f = f/100
  print("Divided by 100:", f)  # gradual underflow

print("\nNum decimal digits <", math.log10(2**53))
         # 15.954589770191003

print()
print("0.1 + 0.2 =", 0.1 + 0.2)
print("0.1 + 0.1 + 0.1 == 0.3? ", (0.1 + 0.1 + 0.1 == 0.3))
print(f"18 dp 0.1 = {0.1:.18f}")
print(f"18 dp 0.2 = {0.2:.18f}")
print(f"18 dp 0.3 = {0.3:.18f}")
print("math.isclose() for 0.1 + 0.1 + 0.1 == 0.3? ", 
                  math.isclose(0.1 + 0.1 + 0.1, 0.3))

print()
printIEEE754(0.1)
printIEEE754(0.2)
printIEEE754(0.3)

print()
a = "01100110011001100110011001100110011001100110011001101"
      # 0.1 mantissa shifted 1 right; unnormalized
b = "11001100110011001100110011001100110011001100110011010"
      # 0.2 mantissa unchanged; unnormalized
print("    a =", a)
print("    b =", b)
print("a + b =", addBinary(a,b))
   # 100110011001100110011001100110011001100110011001100111
   # normalize, truncate last digit


# only in Python 3.9+
print()
for i in range(-5, 10):
  nxt = math.nextafter(10**i, float('inf'))
  print(f"next after {10**i} = {nxt}")
  print(" ulp =", math.ulp(nxt))

print()
val = 10**10
printIEEE754(val)
printIEEE754(math.nextafter(val, float('inf')))


print()
print("(0.7 + 0.1) + 0.3 =", (0.7 + 0.1) + 0.3)
     # 1.0999999999999999
print("0.7 + (0.1 + 0.3) =", 0.7 + (0.1 + 0.3))  # 1.1

print()
xt = 1e20; yt = -1e20; zt = 1
print("xt=", xt, "; yt=", yt, "; zt=", zt)
print("(xt + yt) + zt =", (xt + yt) + zt)  # 1.0
print("xt + (yt + zt) =", xt + (yt + zt))   # 0.0

print()
print(float('nan'))
print(float('inf'))
print(float('-inf'))
print("inf == inf =", float('Inf') == float('Inf'))  # True
print("inf == 1 =", float('Inf') == 1)   # False
print("inf - inf =", float('Inf') - float('Inf'))  # nan
print("Check for nan =", math.isnan(float('nan')))   # True
print("Check for inf =", math.isinf(float('inf')))   # True
try:
  print("float 5/0 =", 5/0)
except Exception as e:
  print(e)  # division by zero error


print("\nCount down to 0:")
a = 2
while a != 0:
  print(a, end= ' ')
  a -= 0.1
  if a < -2:
    print("\nReached -2!")
    break
