#!/bin/env python3
import math
import sys

def normalize_float( num: float ) -> float:
    num = math.fabs(num)
    power = math.floor(math.log10(num))
    # return num * 10**-power, power
    return num, power


def last_grad_mark_C( num: int ) -> int:
    if num < 1:
        return 1
    if num < 200:
        return int(num)
    if num < 500:
        return int(num / 2) * 2
    if num < 1000:
        return int(num / 5) * 5
    if num < 2000:
        return int(num / 10) * 10
    if num < 5000:
        return int(num / 20) * 20
    if num < 10000:
        return int(num / 50) * 50
    if num < 20000:
        return int(num / 100) * 100
    if num < 50000:
        return int(num / 200) * 200
    return int(num / 500) * 500

def next_grad_mark_C( num: int ) -> int:
    if num < 200:
        return num + 1
    if num < 500:
        return num + 2
    if num < 1000:
        return num + 5
    if num < 2000:
        return num + 10
    if num < 5000:
        return num + 20
    if num < 10000:
        return num + 50
    if num < 20000:
        return num + 100
    if num < 50000:
        return num + 200
    return num + 500

def ratio_error( target: float, n: int, d: int ):
    return (target-(float(n)/float(d)))**2
    #return (math.atan(target)-math.atan(float(n)/float(d)))**2
    #ta = math.atan(target)
    #return math.fabs(ta-math.atan(float(n)/float(d)))/ta


def find_ratio( target: float, verbose = True ):
    guessN = 1
    guessD = 1
    error = ratio_error(target, guessN, guessD)
    if verbose:
        print( f"{guessN}/{guessD} = {(float(guessN)/float(guessD))}" )
    i = 1
    while i <= 100000 and i <= (100000 * target) :
        j = last_grad_mark_C(i / target)
        for _ in range(3):
            new_error = ratio_error(target, i, j)
            if new_error == error and verbose:
                print( f"or {i}/{j} = {(float(i)/float(j))}" )
            elif new_error < error:
                if verbose:
                    print( f"{i}/{j} = {(float(i)/float(j))}" )
                error = new_error
                guessN = i
                guessD = j
            j = next_grad_mark_C( j )
        i = next_grad_mark_C( i )
    return (guessN, guessD)


# print(normalize_float(-1.2345e-5))
# print(normalize_float(-1.2345e5))
# print(normalize_float(1.2345e-5))
# print(normalize_float(1.2345e5))
# print(normalize_float(math.e))
# print(normalize_float(math.pi))
# print(normalize_float(math.tau))

#target, power = normalize_float(math.e)
#target, power = normalize_float(math.pi)
#target, power = normalize_float(math.tau)
#target, power = normalize_float(1.6180339887498948) #phi
#target, power = normalize_float(360/math.tau) # degrees to radians
#target, power = normalize_float(6.67408e-11) # Gravitational constant
#target, power = normalize_float(6.62607015e-34) # Plank constant
#target, power = normalize_float(1.380649e-23) # Boltzmann constant
#target, power = normalize_float(7.2973525664e-3) # Fine Structure constant
#target, power = normalize_float(8.8541878188e-12) # Vacuum permittivity constant
#target, power = normalize_float(1.25663706127e-6) # vacuum permeability constant
#target, power = normalize_float(96485.33289) # Faraday constant
#target, power = normalize_float(9192631770) # Cesium 133 hyperfine state oscillation rate
#target, power = normalize_float(683) # Candela constant of luminous intensity at 5.40THz(~555 nm)


#target, power = normalize_float(299792458) #  speed of light
#target, power = normalize_float(1.602176634e-19) #  Electron Charge
#target, power = normalize_float(6.02214076e23) # Avogadro's Number

#target, power = normalize_float(1728/231) # gallons/cubic foot
#target, power = normalize_float(2.54*2.54*2.54) # cubic cm/cubic in
#target, power = normalize_float(2.54*2.54*2.54*231) # cubic cm/gallon
#target, power = normalize_float(5280*12*.0000254) # km / mile
#target, power = normalize_float(5280*12*.0254/3600) # mps / mile per hour
#target, power = normalize_float(36/10) # km per hour / mps
#target, power = normalize_float(1.852) # km / nuatical miles
target, power = normalize_float(1.852/(5280*12*.0000254)) # mi / nuatical miles

#target, power = normalize_float(365.2422) #  constant
#target, power = 6.83 #  constant
#target, power = normalize_float() #  constant
#target, power = normalize_float() #  constant
#target, power = normalize_float() #  constant

if len(sys.argv) > 2:
    target, power = normalize_float(float(sys.argv[1])/float(sys.argv[2]))
elif len(sys.argv) > 1:
    target, power = normalize_float(float(sys.argv[1]))

#T = [ target, target* 10, target / 10.0, target ** -1, (target ** -1) * 10 ]
T = [ target * 10**-(power-3+x) for x in range(7) ]
T = T + [ target**-1 * 10**(power-3+x) for x in range(7) ]
N = [0] * len(T)
D = [0] * len(T)

print( "\n"*10 )

for idx, t in enumerate(T):
    print( f"\n\nTarget is: {t}" )
    N[idx], D[idx] = find_ratio( t )

print( "Summary:" )
print( f" Power = {power}" )
for idx, t in enumerate(T):
    print( f" {t} - {N[idx]}/{D[idx]} = \t{(t-(float(N[idx])/float(D[idx])))/t} \tor {ratio_error(t, N[idx], D[idx])}" )
