Arithmetic/Rational: Difference between revisions

Content added Content deleted
(→‎{{header|jq}}: add r_to_decimal)
(→‎{{header|jq}}: simpler r_to_decimal/1)
Line 1,998: Line 1,998:
in the case of requal/2.
in the case of requal/2.


'''module "Rational";'''
'''module {"name": "Rational"};'''
<lang jq># a and b are assumed to be non-zero integers
<lang jq># a and b are assumed to be non-zero integers
def gcd(a; b):
def gcd(a; b):
Line 2,126: Line 2,126:
def r_to_decimal: .n / .d;
def r_to_decimal: .n / .d;


# Input: a Rational, {n, d} or a number
# Input: a Rational, or {n, d} in general, or an integer.
# Output: a string representation of the input as a decimal number.
# Output: a string representation of the input as a decimal number.
# If the input is a number, it is simply converted to a string.
# If the input is a number, it is simply converted to a string.
# Otherwise, $precision determines the number digits af precision after the decimal point,
# Otherwise, $precision determines the number of digits after the decimal point,
# obtained by truncating, but trailing 0s are omitted.
# excluding trailing 0s. Trailing 0s are only included if they arise because of truncation.
# Examples assuming $digits is 5:
def r_to_decimal($precision):
# -0//1 => "0"
# Examples assuming $precision is 5:
# 0/1 => "0"
# 2//1 => "2"
# 2/1 => "2"
# 1//2 => "0.5"
# 1/2 => "0.5"
# 1//3 => "0.33333"
# 1/3 => "0.33333"
# 7//9 => "0.77777"
# 1/10 => "0.1"
# 1//100 => "0.01"
# 1/1000000 => "0.00000"
# -1//10 => "-0.1"
# 1/100000000 => "0.00000"
# 1//1000000 => "0."
def r_to_decimal($digits):
if type == "number" then tostring
if .n == 0 # captures the annoying case of -0
else . as {n: $m, d: $n}
then "0"
| if $n == 0 then "denominator cannot be 0" | error
elif $n < 0 then r(-$m;-$n) | r_to_decimal($precision)
elif type == "number" then tostring
elif $m < 0 then r(-$m; $n) | r_to_decimal($precision) | .[0] |= ("-" + .)
elif .d < 0 then {n: -.n, d: -.d}|r_to_decimal($digits)
elif .n < 0
else ($m | idivide($n) | tostring + ".") as $quotient
then "-" + ((.n = -.n) | r_to_decimal($digits))
| {c: (($m % $n) * 10), $quotient, i: 0 }
else (10|power($digits)) as $p
| until (.c <= 0 or .c >= $n or .i >= $precision; .c *= 10 | .i += 1 | .quotient += "0")
| ($precision - .i) as $digits
| .d as $d
| . + { emit: false, tail: "" }
| if $d == 1 then .n|tostring
else ($p * .n | idivide($d) | tostring) as $n
| until (.emit;
if (.tail | length) >= $digits
| ($n|length) as $nlength
| (if $nlength > $digits then $n[0:$nlength-$digits] + "." + $n[$nlength-$digits:]
then .emit = {quotient, tail}
else .q = (.c | idivide($n))
else "0." + ("0"*($digits - $nlength) + $n)
| .r = .c % $n
end) | sub("0+$";"")
end
| .tail += (.q|tostring)
end;
| .c = .r * 10
end
)
end
| .emit
# remove trailing zeros from tail
| .tail |= sub("0+$"; "")
| if (.tail|length) > 0
then .quotient + .tail
else (.quotient | sub("[.]$"; ""))
end
end ;


# pretty print ala Julia
# pretty print ala Julia