
# decimalTests.py

import math

import decimal
from decimal import Decimal as D


def fpi(): 
  pi = 0.0 
  for k in range(350): 
    pi += (4.0/(8*k+1) - 2.0/(8*k+4) - 1.0/(8*k+5) - 1.0/(8*k+6)) / 16.0**k 
  return pi 

def dpi():
  with decimal.localcontext() as ctx:
    ctx.prec = 100  # 100 digits precision
    pi = D(0)
    for k in range(350):
      pi += (D(4)/(D(8)*k+D(1)) - D(2)/(D(8)*k+D(4)) - 
             D(1)/(D(8)*k+D(5)) - D(1)/(D(8)*k+D(6))) / D(16)**k 
    return pi 

# -----------------------------

print("Decimal context:\n", decimal.getcontext())
# decimal.getcontext().prec = 100

print()
x = D('0.1')
print("Str 0.1:", x)
y = D('0.3')
res = x + x + x
print("Decimal str 0.1 + 0.1 + 0.1 == 0.3? ", (res == y), res)

x = D(0.1)
print("\nfloat 0.1:", x)
y = D(0.3)
res = x + x + x
print("Decimal float 0.1 + 0.1 + 0.1 == 0.3? ", (res == y), res)
print("5dp Rounded Decimal float 0.1 + 0.1 + 0.1 == 0.3? ", 
                (round(res,5) == round(y,5)), round(res,5))

print()
try:
  print("decimal 5/0 =", D(5)/D(0))
except Exception as e:
  print(e)  # decimal.DivisionByZero error

print()
print("decimal + int:", D('3.333') + 1)
try:
  print("decimal + float", D('3.333') + 1.5)
except Exception as e:
  print(e)  # unsupported operand error
print("decimal + converted float:", D('3.333') + D('1.5'))

print()
d = D("10.005")
print("Value:", d)
print("2 dps rounded:", d.quantize(D("1.00"))) # 10.00
print("2 dps rounded up:", d.quantize(D("1.00"), decimal.ROUND_HALF_UP)) # 10.01


print()
big = 1E30
small = 1E-20
print(f"float {big} - {small} = {big - small}")
with decimal.localcontext() as ctx:
  ctx.prec=100
  print(f"100 precision numerical decimal {big} - {small} = \n{D(big) - D(small)}")
  print(f"100 precision string decimal {big} - {small} = \n{D('1E30') - D('1E-20')}")

print()
print("math sqrt 2 squared =", math.sqrt(2)**2)
print("decimal sqrt 2 squared =", D(2).sqrt()**2)

print()
print("math exp 1 =", math.exp(1))
print("decimal exp 1 =", D(1).exp())

print()
try:
  print("math.exp(1000): ", end='')
  print(math.exp(1000))
except OverflowError as oe:
  print("... overflow: ", oe)
print("Decimal.exp(1000): ", D("1000").exp())

print("\nmath.exp(-1000): ", math.exp(-1000))
print("Decimal.exp(-1000): ", D("-1000").exp())

print()
print("     math.pi:", math.pi)
print("Decimal pi():", dpi())
print("Float pi(): ", end='')
try:
  print(fpi())
except OverflowError as oe:
  print("... overflow: ", oe)


