Getting the number of decimal places
Write a program (function) to get the number of decimals in a given number.
Examples:
for num = 12.345 decimals = 3 and for num = 12.3450 decimals = 4
Go
<lang go>package main
import (
"fmt" "log" "math" "strings"
)
var error = "Argument must be a numeric literal or a decimal numeric string."
func getNumDecimals(n interface{}) int {
switch v := n.(type) { case int: return 0 case float64: if v == math.Trunc(v) { return 0 } s := fmt.Sprintf("%g", v) return len(strings.Split(s, ".")[1]) case string: if v == "" { log.Fatal(error) } if v[0] == '+' || v[0] == '-' { v = v[1:] } for _, c := range v { if strings.IndexRune("0123456789.", c) == -1 { log.Fatal(error) } } s := strings.Split(v, ".") ls := len(s) if ls == 1 { return 0 } else if ls == 2 { return len(s[1]) } else { log.Fatal("Too many decimal points") } default: log.Fatal(error) } return 0
}
func main() {
var a = []interface{}{12, 12.345, 12.345555555555, "12.3450", "12.34555555555555555555", 12.345e53} for _, n := range a { d := getNumDecimals(n) switch v := n.(type) { case string: fmt.Printf("%q has %d decimals\n", v, d) case float32, float64: fmt.Printf("%g has %d decimals\n", v, d) default: fmt.Printf("%d has %d decimals\n", v, d) } }
}</lang>
- Output:
12 has 0 decimals 12.345 has 3 decimals 12.345555555555 has 12 decimals "12.3450" has 4 decimals "12.34555555555555555555" has 20 decimals 1.2345e+54 has 0 decimals
Raku
Raku does not specifically have a "decimal" number type, however we can easily determine the fractional precision of a rational number. It is somewhat touchy-feely for floating point numbers; (what is the fractional precision for 2.45e-12?), it's pretty pointless for Integers; (zero, aalllways zero...), but Rats (rationals) are doable. Note that these are (mostly) actual numerics, not numeric strings. The exception is '12.3450'. That is a numeric string since actual numerics automatically truncate non-significant trailing zeros. If you want to retain them, you need to pass the value as a string. (As below.)
<lang perl6>use Rat::Precise;
printf "Fractional precision: %-2s || Number: %s\n", (.split('.')[1] // ).chars, $_
for 9, 12.345, '12.3450', 0.1234567890987654321, (1.5**63).precise;
</lang>
- Output:
Fractional precision: 0 || Number: 9 Fractional precision: 3 || Number: 12.345 Fractional precision: 4 || Number: 12.3450 Fractional precision: 19 || Number: 0.1234567890987654321 Fractional precision: 63 || Number: 124093581919.648947697827373650380188008224280338254175148904323577880859375
Ring
<lang ring>
- Testing the function
decimals(2) # Unsensitive to the default setting of decimals n = 5.1945 ? NbrOfDecimals(n) # Gives 4
func NbrOfDecimals(n) nTemp = 1 nNbrOfDecimals = 0 while True if nNbrOfDecimals < 9 nNbrOfDecimals++ nTemp *= 10 nTemp1 = n * nTemp - ceil( n * nTemp ) if nTemp1 = 0 return nNbrOfDecimals ok else raise("Acceeding the maximum number of 9 decimals!") ok end </lang>
- Output:
4
Wren
In the following script, the fourth and fifth examples need to be expressed as strings to avoid getting the wrong answer. If we use numbers instead, trailing zeros will be automatically removed and the result will be rounded to 14 significant figures when stringified or printed.
Converting the fourth example to a Rat or BigRat object wouldn't help as the constructor for those classes automatically reduces the numerator and denominator to their lowest terms. BigRat would work for the fifth example but the argument would have to be passed as a string anyway so we might as well just parse the string. <lang ecmascript>var error = "Argument must be a number or a decimal numeric string."
var getNumDecimals = Fn.new { |n|
if (n is Num) { if (n.isInteger) return 0 n = n.toString } else if (n is String) { if (n == "") Fiber.abort(error) if (n[0] == "+" || n[0] == "-") n = n[1..-1] if (!n.all { |c| "0123456789.".contains(c) }) Fiber.abort(error) } else { Fiber.abort(error) } var s = n.split(".") var c = s.count return (c == 1) ? 0 : (c == 2) ? s[1].count : Fiber.abort("Too many decimal points.")
}
var a = [12, 12.345, 12.345555555555, "12.3450", "12.34555555555555555555", 12.345e53] for (n in a) {
var d = getNumDecimals.call(n) var ns = (n is String) ? "\"%(n)\"" : "%(n)" System.print("%(ns) has %(d) decimals")
}</lang>
- Output:
12 has 0 decimals 12.345 has 3 decimals 12.345555555555 has 12 decimals "12.3450" has 4 decimals "12.34555555555555555555" has 20 decimals 1.2345e+54 has 0 decimals