|
|
@@ -0,0 +1,127 @@ |
|
|
import numba |
|
|
import numpy as np |
|
|
import numba |
|
|
from numba import types, jit,njit, generated_jit |
|
|
from numba import deferred_type, optional |
|
|
from numba import void,b1,u1,u2,u4,u8,i1,i2,i4,i8,f4,f8,c8,c16 |
|
|
from numba.typed import List, Dict |
|
|
from numba.types import ListType, unicode_type, UnicodeType |
|
|
from numba.cpython.unicode import _empty_string, _set_code_point, _get_code_point, PY_UNICODE_1BYTE_KIND |
|
|
from numba.extending import overload, overload_method |
|
|
|
|
|
DIGITS_START = 48 |
|
|
DIGITS_END = 58 |
|
|
DASH = 45 |
|
|
DOT = 46 |
|
|
PLUS = 43 |
|
|
E_CHAR = 101 |
|
|
|
|
|
@njit(cache=True) |
|
|
def get_n_digits(x): |
|
|
l1,l2 = 0,-1 |
|
|
_x = x |
|
|
while _x > 0: |
|
|
_x = _x // 10 |
|
|
l1 += 1 |
|
|
|
|
|
_x = x % 10 |
|
|
while _x > 1e-10: |
|
|
_x = (_x * 10) % 10 |
|
|
l2 += 1 |
|
|
if(l2 >= 16): break |
|
|
return l1, l2 |
|
|
|
|
|
@njit |
|
|
def float_to_str(x): |
|
|
if(x == np.inf): |
|
|
return 'inf' |
|
|
elif(x == -np.inf): |
|
|
return '-inf' |
|
|
|
|
|
isneg = int(x < 0.0) |
|
|
x = np.abs(x) |
|
|
|
|
|
if(x != 0.0): |
|
|
# There is probably a more efficient way to do this |
|
|
e = np.floor(np.log10(x)) |
|
|
if(10**e - x > 0): e -= 1 |
|
|
else: |
|
|
e = 0 |
|
|
|
|
|
is_exp, is_neg_exp = e >= 16, e <= -16 |
|
|
|
|
|
exp_chars = 0 |
|
|
if (is_exp or is_neg_exp): |
|
|
exp_chars = 4 |
|
|
if(e >= 100 or e <= -100): exp_chars = 5 |
|
|
|
|
|
|
|
|
if(is_exp): |
|
|
offset_x = np.around(x * (10.0**-(e)),15) |
|
|
l1, l2 = get_n_digits(offset_x) |
|
|
elif(is_neg_exp): |
|
|
offset_x = np.around(x * (10**-(e)),15) |
|
|
l1, l2 = get_n_digits(offset_x) |
|
|
else: |
|
|
offset_x = x |
|
|
l1,l2 = get_n_digits(x) |
|
|
l2 = max(1,l2) # Will have at least .0 |
|
|
|
|
|
use_dec = l2 > 0 |
|
|
|
|
|
# print("<<", e, offset_x, l2) |
|
|
|
|
|
l = l1+l2+use_dec |
|
|
length = l+isneg+exp_chars |
|
|
s = _empty_string(PY_UNICODE_1BYTE_KIND,length) |
|
|
if(isneg): _set_code_point(s,0,DASH) |
|
|
|
|
|
_x = offset_x |
|
|
for i in range(l1): |
|
|
digit = int(_x % 10) |
|
|
_set_code_point(s,(isneg+l1)-i-1,digit + DIGITS_START) |
|
|
_x = _x // 10 |
|
|
|
|
|
if(use_dec): |
|
|
_set_code_point(s,l1+isneg,DOT) |
|
|
|
|
|
_x = offset_x % 10 |
|
|
for i in range(l2): |
|
|
_x = (_x * 10) % 10 |
|
|
digit = int(_x) |
|
|
|
|
|
_set_code_point(s,(isneg+l1)+i+use_dec,digit + DIGITS_START) |
|
|
|
|
|
if(is_exp or is_neg_exp): |
|
|
i = (isneg+l1+use_dec+l2) |
|
|
_set_code_point(s,i,E_CHAR) |
|
|
if(is_exp): |
|
|
_set_code_point(s,i+1,PLUS) |
|
|
if(is_neg_exp): |
|
|
_set_code_point(s,i+1,DASH) |
|
|
|
|
|
i = length-1 |
|
|
exp = np.abs(e) |
|
|
while(exp > 0): |
|
|
digit = exp % 10 |
|
|
_set_code_point(s,i,digit + DIGITS_START) |
|
|
exp = exp // 10 |
|
|
i -= 1 |
|
|
|
|
|
return s |
|
|
|
|
|
# Monkey Patch type conversions so that float(str) and str(float) |
|
|
# work like in normal python |
|
|
|
|
|
@overload_method(types.Float, '__str__') |
|
|
def overload_float_to_str(x): |
|
|
def impl(x): |
|
|
return float_to_str(x) |
|
|
return impl |
|
|
|
|
|
@njit |
|
|
def test(x): |
|
|
s = "This is the number: " + str(x) |
|
|
return s |
|
|
|
|
|
print(test(-1.9)) |