-
Notifications
You must be signed in to change notification settings - Fork 1
/
binary.py
97 lines (74 loc) · 3.43 KB
/
binary.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import math
import numpy as np
def float_to_binary(number: float, tolerance: float) -> str:
if not isinstance(number, float):
raise ValueError(f'Number need to be float but got: {type(number)}')
if not isinstance(tolerance, float):
raise ValueError(f'Tolerance need to be float but got: {type(tolerance)}')
int_part = math.floor(number)
frac_part = number - int_part
int_bin = bin(int_part)[2:] if int_part != 0 else '0'
frac_bin = ''
while len(frac_bin) < tolerance:
frac_part *= 2
if frac_part >= 1:
frac_bin += '1'
frac_part -= 1
else:
frac_bin += '0'
return f'{int_bin}.{frac_bin}'
def find_upper_and_lower_approximation(number: float, tolerance: float) -> tuple[float, str, float, str]:
if not isinstance(number, float):
raise ValueError(f'Number need to be float but got: {type(number)}')
if not isinstance(tolerance, float):
raise ValueError(f'Tolerance need to be float but got: {type(tolerance)}')
binary_rep = float_to_binary(number, tolerance)
_, r = binary_fraction_to_exponent(binary_rep)
tolerance -= r
lower_value = math.floor(number * 2 ** tolerance) / 2 ** tolerance
lower_bin = float_to_binary(lower_value, tolerance)
upper_value = math.ceil(number * 2 ** tolerance) / 2 ** tolerance
upper_bin = float_to_binary(upper_value, tolerance)
return lower_value, lower_bin, upper_value, upper_bin
def main(number: float, tolerance: float):
if not isinstance(number, float):
raise ValueError(f'Number need to be float but got: {type(number)}')
if not isinstance(tolerance, float):
raise ValueError(f'Tolerance need to be float but got: {type(tolerance)}')
lower_value, lower_bin, upper_value, upper_bin = find_upper_and_lower_approximation(number, tolerance)
_ = float_to_binary(number, tolerance)
print(f"Dolne przybliżenie: {lower_value}, w postaci dwójkowej: {lower_bin}")
print(f"Górne przybliżenie: {upper_value}, w postaci dwójkowej: {upper_bin}")
error_lower = abs(number - lower_value)
error_upper = abs(number - upper_value)
low = True if error_lower <= error_upper else False
if low:
answer = lower_bin
else:
answer = upper_bin
print(f"Liczba {number} w postaci dwójkowej z precyzją {tolerance} bitów: {answer}")
print(f"Błąd przybliżenia w |x - Fl(x)| = {error_lower if low else error_upper}")
def binary_fraction_to_exponent(binary_fraction: str) -> tuple[float, float]:
if not isinstance(binary_fraction, str):
raise ValueError(f"Binary fraction need to be str but got: {type(binary_fraction)}")
if '.' not in binary_fraction:
raise ValueError("Liczba musi być w postaci ułamka (z kropką).")
int_part, frac_part = binary_fraction.split('.')
binary_number = int_part + frac_part
if int(binary_number) == 0:
raise ValueError("Liczba nie może być zerem.")
if '1' in int_part:
first_one_index = int_part.index('1')
exponent = len(int_part) - first_one_index - 1
mantissa = int_part[first_one_index + 1:] + frac_part
else:
first_one_index = frac_part.index('1')
exponent = -(first_one_index + 1)
mantissa = frac_part[first_one_index + 1:]
normalized_mantissa = '1.' + mantissa
return normalized_mantissa, exponent
if __name__ == '__main__':
x = 2 / 3
y = np.float32(x)
t = 23
main(y, t)