bootstrapworld / curriculum

6 stars 6 forks source link

Improve num-to-sci in Bootstrap-DataScience library #2125

Closed schanzer closed 1 week ago

schanzer commented 1 month ago

Link to the full context

#################################################
# Log functions
fun round-digits(val, digits):
  num-round(val * num-expt(10, digits)) / num-expt(10, digits)
where:
  round-digits(1.24, 1) is 1.2
  round-digits(num-sqrt(2), 3) is 1.414
end

fun log-base(base, val):
  lg = num-log(val) / num-log(base)
  lg-round = round-digits(lg, 4)
  if roughly-equal(lg-round, lg) and roughly-equal(num-expt(base, lg-round), val):
    lg-round
  else:
    lg
  end
where:
  log-base(3, 9) is 2
  log-base(3, 1/9) is -2
  num-log(9) / num-log(3) satisfies num-is-roughnum
  log-base(4, 32) is 2.5
end

fun log(n): log-base(10, n) end
ln = num-log

fun num-to-sci(n :: Number, max-chars :: Number) block:
  fixed = num-to-fixnum(n)
  rough = ~1 * n
  rough-str = num-to-string(rough)
  digits-after-decimal = if (num-exact(n) == 0): 1 
  else: num-ceiling(log-base(10, num-abs(n)))
  end
  str = if (num-is-roughnum(n) and (num-abs(rough) < num-expt(10, max-chars))):
    string-substring(rough-str, 0, num-min(num-max(digits-after-decimal + 4, max-chars), string-length(rough-str)))
  else if (not(num-is-roughnum(n)) and 
      (string-to-number(num-to-string(fixed)) == string-to-number(num-to-string(n)))):
    num-to-string(fixed)
  else if num-is-roughnum(n):
    rough-str
  else if (num-is-fixnum(n) or not(num-is-integer(n))): 
    num-to-string(fixed)
  else: 
    num-to-string(n)
  end
  #display("absolute string:" + str)
  #  display("digits-after-decimal:" + num-to-string(digits-after-decimal))
  # report zeros normally
  if (num-exact(n) == 0): "0"
  else if ((string-length(str) > max-chars) and (num-abs(digits-after-decimal) > 4)):
    block:
      #display("shift needed")
      shift = digits-after-decimal - 3 # for X.YZ
      sig = n / num-expt(10, shift)
      sigStr = num-to-string-digits(sig / 100, 2)
      sigStr + "e" + num-to-string(shift + 2)
    end
  else: 
    shadow max-chars = max-chars - if (n < 0): 1 else: 0 end
    string-substring(str, 0, num-min(string-length(str), max-chars))
  end
where:
  num-to-sci(0.00000343, 10) is "0.00000343" # max fixnum size (small)
  num-to-sci(0.000000343, 11) is "3.43e-7" 
  num-to-sci(0.00000343, 9) is "3.43e-6"
  num-to-sci(4564634745675734, 16) is "4564634745675734" # max fixnum size (big)
  num-to-sci(45646347456757342, 17) is "45646347456757342"
  num-to-sci(45646347456757342, 16) is "4.56e16" 
  num-to-sci(4564634745675734, 15) is "4.56e15" 
  num-to-sci(-45646347456757342.000343, 16) is "-4.56e16"
  num-to-sci(0.000001, 8) is "0.000001"
  num-to-sci(-0.000001, 8) is "-10.00e-7"
  num-to-sci(1/3, 18) is "0.3333333333333333"
  num-to-sci(1/3, 19) is "0.3333333333333333" # extra char is unused due to fixnum precision
  num-to-sci(1/3, 8) is "0.333333"
end
ds26gte commented 1 month ago

Could you write up what is expected? Thanks.

schanzer commented 1 month ago

@ds26gte the function should return a string representation of any number, which meets the following criteria: