imaginary_base_numbers.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Imaginary_base_numbers
  4. #
  5. func base (Number num, Number radix { _ ~~ (-36 .. -2) }, precision = -15) -> String {
  6. num || return '0'
  7. var place = 0
  8. var result = ''
  9. var value = num
  10. var upper_bound = 1/(-radix + 1)
  11. var lower_bound = radix*upper_bound
  12. while (!(lower_bound <= value) || !(value < upper_bound)) {
  13. value = num/(radix**++place)
  14. }
  15. while ((value || (place > 0)) && (place > precision)) {
  16. var digit = (radix*value - lower_bound -> int)
  17. value = (radix*value - digit)
  18. result += '.' if (!place && !result.contains('.'))
  19. result += ((digit == -radix) ? (digit-1 -> base(-radix) + '0') : digit.base(-radix))
  20. place--
  21. }
  22. return result
  23. }
  24. func base (Number num, Number radix { .re == 0 }, precision = -8) -> String {
  25. (radix.im.abs ~~ 2..6) || die "Base #{radix} out of range"
  26. var (re, im) = (num.re, num.im)
  27. var (re_wh, re_fr='') = base(re, -radix.im**2, precision).split('.')...
  28. var (im_wh, im_fr='') = base(im/radix.im, -radix.im**2, precision).split('.')...
  29. func zip (String a, String b) {
  30. var l = ('0' * abs(a.len - b.len))
  31. chars(a+l) ~Z chars(b+l) -> flat.join.sub(/0+\z/, '') || '0'
  32. }
  33. var whole = zip(re_wh.flip, im_wh.flip).flip
  34. var fraction = zip(im_fr, re_fr)
  35. fraction == '0' ? whole : "#{whole}.#{fraction}"
  36. }
  37. func parse_base (String str, Number radix { .re == 0 }) -> Number {
  38. if (str.char(0) == '-') {
  39. return (-1 * parse_base(str.substr(1), radix))
  40. }
  41. var (whole, frac='') = str.split('.')...
  42. var fraction = frac.chars.map_kv {|k,v|
  43. Number(v, radix.im**2) * radix**-(k+1)
  44. }.sum
  45. fraction += whole.flip.chars.map_kv {|k,v|
  46. Number(v, radix.im**2) * radix**k
  47. }.sum
  48. return fraction
  49. }
  50. var tests = [0, 2i, 1, 2i, 5, 2i, -13, 2i, 9i, 2i, -3i, 2i, 7.75-7.5i, 2i, .25, 2i, # base 2i tests
  51. 5+5i, 2i, 5+5i, 3i, 5+5i, 4i, 5+5i, 5i, 5+5i, 6i, # same value, positive imaginary bases
  52. 5+5i, -2i, 5+5i, -3i, 5+5i, -4i, 5+5i, -5i, 5+5i, -6i, # same value, negative imaginary bases
  53. 227.65625+10.859375i, 4i] # larger test value
  54. tests.each_slice(2, {|v,r|
  55. var ibase = base(v, r)
  56. printf("base(%20s, %2si) = %-10s : parse_base(%12s, %2si) = %s\n",
  57. v, r.im, ibase, "'#{ibase}'", r.im, parse_base(ibase, r).round(-8))
  58. })
  59. assert_eq(base(tests[-2], tests[-1]), "10234.5678")
  60. assert_eq(parse_base("10234.5678", tests[-1]).round(-8), 227.65625+10.859375i)