generic_float.odin 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. package strconv
  2. using import "decimal"
  3. Int_Flag :: enum {
  4. Prefix,
  5. Plus,
  6. Space,
  7. }
  8. Int_Flags :: bit_set[Int_Flag];
  9. Decimal_Slice :: struct {
  10. digits: []byte,
  11. count: int,
  12. decimal_point: int,
  13. neg: bool,
  14. }
  15. Float_Info :: struct {
  16. mantbits: uint,
  17. expbits: uint,
  18. bias: int,
  19. }
  20. _f16_info := Float_Info{10, 5, -15};
  21. _f32_info := Float_Info{23, 8, -127};
  22. _f64_info := Float_Info{52, 11, -1023};
  23. generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
  24. bits: u64;
  25. flt: ^Float_Info;
  26. switch bit_size {
  27. case 32:
  28. bits = u64(transmute(u32)f32(val));
  29. flt = &_f32_info;
  30. case 64:
  31. bits = transmute(u64)val;
  32. flt = &_f64_info;
  33. case:
  34. panic("strconv: invalid bit_size");
  35. }
  36. neg := bits>>(flt.expbits+flt.mantbits) != 0;
  37. exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
  38. mant := bits & (u64(1) << flt.mantbits - 1);
  39. switch exp {
  40. case 1<<flt.expbits - 1:
  41. s: string;
  42. if mant != 0 {
  43. s = "NaN";
  44. } else if neg {
  45. s = "-Inf";
  46. } else {
  47. s = "+Inf";
  48. }
  49. n := copy(buf, cast([]byte)s);
  50. return buf[:n];
  51. case 0: // denormalized
  52. exp += 1;
  53. case:
  54. mant |= u64(1) << flt.mantbits;
  55. }
  56. exp += flt.bias;
  57. d_: Decimal;
  58. d := &d_;
  59. assign(d, mant);
  60. shift(d, exp - int(flt.mantbits));
  61. digs: Decimal_Slice;
  62. prec := precision;
  63. shortest := prec < 0;
  64. if shortest {
  65. round_shortest(d, mant, exp, flt);
  66. digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
  67. switch fmt {
  68. case 'e', 'E': prec = digs.count-1;
  69. case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
  70. case 'g', 'G': prec = digs.count;
  71. }
  72. } else {
  73. switch fmt {
  74. case 'e', 'E': round(d, prec+1);
  75. case 'f', 'F': round(d, d.decimal_point+prec);
  76. case 'g', 'G':
  77. if prec == 0 {
  78. prec = 1;
  79. }
  80. round(d, prec);
  81. }
  82. digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
  83. }
  84. return format_digits(buf, shortest, neg, digs, prec, fmt);
  85. }
  86. format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
  87. Buffer :: struct {
  88. b: []byte,
  89. n: int,
  90. };
  91. to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
  92. add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
  93. buf.n += copy(buf.b[buf.n:], bytes);
  94. }
  95. b := Buffer{b = buf};
  96. prec := precision;
  97. switch fmt {
  98. case 'f', 'F':
  99. add_bytes(&b, neg ? '-' : '+');
  100. // integer, padded with zeros when needed
  101. if digs.decimal_point > 0 {
  102. m := min(digs.count, digs.decimal_point);
  103. add_bytes(&b, ..digs.digits[0:m]);
  104. for ; m < digs.decimal_point; m += 1 {
  105. add_bytes(&b, '0');
  106. }
  107. } else {
  108. add_bytes(&b, '0');
  109. }
  110. // fractional part
  111. if prec > 0 {
  112. add_bytes(&b, '.');
  113. for i in 0..<prec {
  114. c: byte = '0';
  115. if j := digs.decimal_point + i; 0 <= j && j < digs.count {
  116. c = digs.digits[j];
  117. }
  118. add_bytes(&b, c);
  119. }
  120. }
  121. return to_bytes(b);
  122. case 'e', 'E':
  123. add_bytes(&b, neg ? '-' : '+');
  124. ch := byte('0');
  125. if digs.count != 0 {
  126. ch = digs.digits[0];
  127. }
  128. add_bytes(&b, ch);
  129. if prec > 0 {
  130. add_bytes(&b, '.');
  131. i := 1;
  132. m := min(digs.count, prec+1);
  133. if i < m {
  134. add_bytes(&b, ..digs.digits[i:m]);
  135. i = m;
  136. }
  137. for ; i <= prec; i += 1 {
  138. add_bytes(&b, '0');
  139. }
  140. }
  141. add_bytes(&b, fmt);
  142. exp := digs.decimal_point-1;
  143. if digs.count == 0 {
  144. // Zero has exponent of 0
  145. exp = 0;
  146. }
  147. ch = '+';
  148. if exp < 0 {
  149. ch = '-';
  150. exp = -exp;
  151. }
  152. add_bytes(&b, ch);
  153. switch {
  154. case exp < 10: add_bytes(&b, '0', byte(exp)+'0'); // add prefix 0
  155. case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0');
  156. case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0');
  157. }
  158. return to_bytes(b);
  159. case 'g', 'G':
  160. eprec := prec;
  161. if eprec > digs.count && digs.count >= digs.decimal_point {
  162. eprec = digs.count;
  163. }
  164. if shortest {
  165. eprec = 6;
  166. }
  167. exp := digs.decimal_point - 1;
  168. if exp < -4 || exp >= eprec {
  169. if prec > digs.count {
  170. prec = digs.count;
  171. }
  172. return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g'); // keep the same case
  173. }
  174. if prec > digs.decimal_point {
  175. prec = digs.count;
  176. }
  177. return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f');
  178. case:
  179. add_bytes(&b, '%', fmt);
  180. return to_bytes(b);
  181. }
  182. }
  183. round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
  184. if mant == 0 { // If mantissa is zero, the number is zero
  185. d.count = 0;
  186. return;
  187. }
  188. /*
  189. 10^(dp-nd) > 2^(exp-mantbits)
  190. log2(10) * (dp-nd) > exp-mantbits
  191. log(2) >~ 0.332
  192. 332*(dp-nd) >= 100*(exp-mantbits)
  193. */
  194. minexp := flt.bias+1;
  195. if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
  196. // Number is already its shortest
  197. return;
  198. }
  199. upper_: Decimal; upper := &upper_;
  200. assign(upper, 2*mant - 1);
  201. shift(upper, exp - int(flt.mantbits) - 1);
  202. mantlo: u64;
  203. explo: int;
  204. if mant > 1<<flt.mantbits || exp == minexp {
  205. mantlo = mant-1;
  206. explo = exp;
  207. } else {
  208. mantlo = 2*mant - 1;
  209. explo = exp-1;
  210. }
  211. lower_: Decimal; lower := &lower_;
  212. assign(lower, 2*mantlo + 1);
  213. shift(lower, explo - int(flt.mantbits) - 1);
  214. inclusive := mant%2 == 0;
  215. for i in 0..<d.count {
  216. l: byte = '0'; // lower digit
  217. if i < lower.count {
  218. l = lower.digits[i];
  219. }
  220. m := d.digits[i]; // middle digit
  221. u: byte = '0'; // upper digit
  222. if i < upper.count {
  223. u = upper.digits[i];
  224. }
  225. ok_round_down := l != m || inclusive && i+1 == lower.count;
  226. ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
  227. if ok_round_down && ok_round_up {
  228. round(d, i+1);
  229. return;
  230. }
  231. if ok_round_down {
  232. round_down(d, i+1);
  233. return;
  234. }
  235. if ok_round_up {
  236. round_up(d, i+1);
  237. return;
  238. }
  239. }
  240. }
  241. MAX_BASE :: 32;
  242. digits := "0123456789abcdefghijklmnopqrstuvwxyz";
  243. is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64, neg: bool) {
  244. u = x;
  245. if is_signed {
  246. switch bit_size {
  247. case 8:
  248. i := i8(u);
  249. neg = i < 0;
  250. u = u64(abs(i64(i)));
  251. case 16:
  252. i := i16(u);
  253. neg = i < 0;
  254. u = u64(abs(i64(i)));
  255. case 32:
  256. i := i32(u);
  257. neg = i < 0;
  258. u = u64(abs(i64(i)));
  259. case 64:
  260. i := i64(u);
  261. neg = i < 0;
  262. u = u64(abs(i64(i)));
  263. case:
  264. panic("is_integer_negative: Unknown integer size");
  265. }
  266. }
  267. return;
  268. }
  269. append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
  270. if base < 2 || base > MAX_BASE {
  271. panic("strconv: illegal base passed to append_bits");
  272. }
  273. a: [129]byte;
  274. i := len(a);
  275. u, neg := is_integer_negative(x, is_signed, bit_size);
  276. b := u64(base);
  277. for u >= b {
  278. i-=1; a[i] = digits[u % b];
  279. u /= b;
  280. }
  281. i-=1; a[i] = digits[u % b];
  282. if .Prefix in flags {
  283. ok := true;
  284. switch base {
  285. case 2: i-=1; a[i] = 'b';
  286. case 8: i-=1; a[i] = 'o';
  287. case 10: i-=1; a[i] = 'd';
  288. case 12: i-=1; a[i] = 'z';
  289. case 16: i-=1; a[i] = 'x';
  290. case: ok = false;
  291. }
  292. if ok {
  293. i-=1; a[i] = '0';
  294. }
  295. }
  296. switch {
  297. case neg:
  298. i-=1; a[i] = '-';
  299. case .Plus in flags:
  300. i-=1; a[i] = '+';
  301. case .Space in flags:
  302. i-=1; a[i] = ' ';
  303. }
  304. out := a[i:];
  305. copy(buf, out);
  306. return string(buf[0:len(out)]);
  307. }
  308. is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: u128, neg: bool) {
  309. u = x;
  310. if is_signed {
  311. switch bit_size {
  312. case 8:
  313. i := i8(u);
  314. neg = i < 0;
  315. u = u128(abs(i128(i)));
  316. case 16:
  317. i := i16(u);
  318. neg = i < 0;
  319. u = u128(abs(i128(i)));
  320. case 32:
  321. i := i32(u);
  322. neg = i < 0;
  323. u = u128(abs(i128(i)));
  324. case 64:
  325. i := i64(u);
  326. neg = i < 0;
  327. u = u128(abs(i128(i)));
  328. case 128:
  329. i := i128(u);
  330. neg = i < 0;
  331. u = u128(abs(i128(i)));
  332. case:
  333. panic("is_integer_negative: Unknown integer size");
  334. }
  335. }
  336. return;
  337. }
  338. append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
  339. if base < 2 || base > MAX_BASE {
  340. panic("strconv: illegal base passed to append_bits");
  341. }
  342. a: [140]byte;
  343. i := len(a);
  344. u, neg := is_integer_negative_128(x, is_signed, bit_size);
  345. b := u128(base);
  346. for u >= b {
  347. i-=1; a[i] = digits[u % b];
  348. u /= b;
  349. }
  350. i-=1; a[i] = digits[u % b];
  351. if .Prefix in flags {
  352. ok := true;
  353. switch base {
  354. case 2: i-=1; a[i] = 'b';
  355. case 8: i-=1; a[i] = 'o';
  356. case 10: i-=1; a[i] = 'd';
  357. case 12: i-=1; a[i] = 'z';
  358. case 16: i-=1; a[i] = 'x';
  359. case: ok = false;
  360. }
  361. if ok {
  362. i-=1; a[i] = '0';
  363. }
  364. }
  365. switch {
  366. case neg:
  367. i-=1; a[i] = '-';
  368. case .Plus in flags:
  369. i-=1; a[i] = '+';
  370. case .Space in flags:
  371. i-=1; a[i] = ' ';
  372. }
  373. out := a[i:];
  374. copy(buf, out);
  375. return string(buf[0:len(out)]);
  376. }