I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

# Getting the number of decimals

Getting the number of decimals is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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

(Note that the reference implementation – in the Ring language – shows a function over a given number rather than a given numeric string, and that the sample values shown above are not enclosed in quotes).

## 11l

Translation of: Python
`F dec(n)   R I ‘.’ C n {n.split(‘.’).last.len} E 0 print(dec(‘12.345’))print(dec(‘12.3450’))`
Output:
```3
4
```

## Action!

`INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit BYTE FUNC FindC(CHAR ARRAY s CHAR c)  BYTE i   FOR i=1 TO s(0)  DO    IF s(i)=c THEN      RETURN (i)    FI  ODRETURN (0) BYTE FUNC DecimalCount(REAL POINTER r)  CHAR ARRAY s(20),sub(20)  BYTE i,dotPos,ePos,count  INT exp   StrR(r,s)  ePos=FindC(s,'E)  IF ePos>0 THEN    ePos==+1    IF s(ePos)='+ THEN      ePos==+1    FI    SCopyS(sub,s,ePos,s(0))    exp=ValI(sub)  ELSE    exp=0  FI  dotPos=FindC(s,'.)  count=0  IF dotPos>0 THEN    FOR i=dotPos+1 TO s(0)    DO      IF s(i)<'0 OR s(i)>'9 THEN        EXIT      FI      count==+1    OD  FI  IF exp<0 THEN    count==-exp  ELSEIF exp<count THEN    count==-exp  ELSE    count=0  FIRETURN (count) PROC Test(REAL POINTER r)  BYTE count   count=DecimalCount(r)  PrintR(r)  PrintF(" has %I decimals%E",count)RETURN PROC Main()  REAL r   Put(125) PutE() ;clear screen  ValR("1234",r) Test(r)  ValR("123.4",r) Test(r)  ValR("12.34",r) Test(r)  ValR("1.234",r) Test(r)  ValR("0.1234",r) Test(r)  ValR("1.234E-3",r) Test(r)  ValR("1.234E-10",r) Test(r)  ValR("1.E-10",r) Test(r)  ValR("1.23456789E10",r) Test(r)RETURN`
Output:
```1234 has 0 decimals
123.4 has 1 decimals
12.34 has 2 decimals
1.234 has 3 decimals
.1234 has 4 decimals
1.234E-03 has 6 decimals
1.234E-10 has 13 decimals
1E-10 has 10 decimals
1.23456789E+10 has 0 decimals
```

## AutoHotkey

`for i, v in [10, "10",  12.345, "12.345", 12.3450, "12.3450"]	output .= v " has " StrLen(StrSplit(v, ".").2) " decimals.`n"MsgBox % output`
Output:
```10 has 0 decimals.
10 has 0 decimals.
12.345 has 3 decimals.
12.345 has 3 decimals.
12.3450 has 4 decimals.
12.3450 has 4 decimals.```

## AWK

` # syntax: GAWK -f GETTING_THE_NUMBER_OF_DECIMALS.AWKBEGIN {    n = split("10,1.,1.0,12.345,12.3450",arr,",")    for (i=1; i<=n; i++) {      s = arr[i]      x = index(s,".")      printf("%s has %d decimals\n",s,x?length(s)-x:x)    }    exit(0)} `
Output:
```10 has 0 decimals
1. has 0 decimals
1.0 has 1 decimals
12.345 has 3 decimals
12.3450 has 4 decimals
```

## C

`#include <stdio.h> int findNumOfDec(double x) {    char buffer[128];    int pos, num;     sprintf(buffer, "%.14f", x);     pos = 0;    num = 0;    while (buffer[pos] != 0 && buffer[pos] != '.') {        pos++;    }    if (buffer[pos] != 0) {        pos++; // skip over the decimal        while (buffer[pos] != 0) {            pos++; // find the end of the string        }        pos--; //reverse past the null sentiel        while (buffer[pos] == '0') {            pos--; // reverse past any zeros        }        while (buffer[pos] != '.') {            num++;            pos--; // only count decimals from this point        }    }    return num;} void test(double x) {    int num = findNumOfDec(x);    printf("%f has %d decimals\n", x, num);} int main() {    test(12.0);    test(12.345);    test(12.345555555555);    test(12.3450);    test(12.34555555555555555555);    test(1.2345e+54);    return 0;}`
Output:
```12.000000 has 0 decimals
12.345000 has 3 decimals
12.345556 has 12 decimals
12.345000 has 3 decimals
12.345556 has 14 decimals
1234500000000000060751116919315055127939946206157864960.000000 has 0 decimals```

## C++

Translation of: C
`#include <iomanip>#include <iostream>#include <sstream> int findNumOfDec(double x) {    std::stringstream ss;    ss << std::fixed << std::setprecision(14) << x;     auto s = ss.str();    auto pos = s.find('.');    if (pos == std::string::npos) {        return 0;    }     auto tail = s.find_last_not_of('0');     return tail - pos;} void test(double x) {    std::cout << x << " has " << findNumOfDec(x) << " decimals\n";} int main() {    test(12.0);    test(12.345);    test(12.345555555555);    test(12.3450);    test(12.34555555555555555555);    test(1.2345e+54);    return 0;}`
Output:
```12 has 0 decimals
12.345 has 3 decimals
12.3456 has 12 decimals
12.345 has 3 decimals
12.3456 has 14 decimals
1.2345e+54 has 0 decimals```

## FreeBASIC

`Function dec(n As Double) As Uinteger    Dim As String c = Str(n)    Return Iif(Instr(c, "."), Len(Mid(c,Instr(c, ".")+1)), 0)End Function Dim As Double n(1 To ...) => {7, 12.00, 12.345, 12.345677, 0.142857142857142} For i As Integer = 1 To Ubound(n)    Print n(i); " has "; dec(n(i)); " decimals"Next iSleep`
Output:
``` 7 has 0 decimals
12 has 0 decimals
12.345 has 3 decimals
12.345677 has 6 decimals
0.142857142857142 has 15 decimals```

## Go

Translation of: Wren
`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)        }    }}`
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
```

`decimal :: String -> Intdecimal [] = 0decimal ('.':xs) = length xsdecimal (_:xs) = decimal xs numDecimal :: Double -> IntnumDecimal = decimal . show main = print . map numDecimal \$ [12.0, 12.345, 12.3450, 12.345555555555, 12.34555555555555555555, 1.2345e+54]`
Output:
`[1,3,3,12,15,7]`

## Java

`public static int findNumOfDec(double x){    String str = String.valueOf(x);    if(str.endsWith(".0")) return 0;    else return (str.substring(str.indexOf('.')).length() - 1);}`

## Julia

`function postprecision(str::String)    s = lowercase(str)    if 'e' in s        s, ex = split(s, "e")        expdig = parse(Int, ex)    else        expdig = 0    end    dig = something(findfirst('.', reverse(s)), 1) - 1 - expdig    return dig > 0 ? dig : 0end postprecision(x::Integer) = 0  postprecision(x::Real, max=22) = postprecision(string(round(Float64(x), digits=max))) testnums = ["0.00100", 0.00100, 001.805, 1.0 / 3, 2//3, 12, 12.345, "12.3450",     "12.34555555555555555555", 1.2345e+54, 1.2345e-08, "1.2345e-08", π] for n in testnums    println("\$n has \$(postprecision(n)) decimals.")end `
Output:
```0.00100 has 5 decimals.
0.001 has 3 decimals.
1.805 has 3 decimals.
0.3333333333333333 has 16 decimals.
2//3 has 16 decimals.
12 has 0 decimals.
12.345 has 3 decimals.
12.3450 has 4 decimals.
12.34555555555555555555 has 20 decimals.
1.2345e54 has 0 decimals.
1.2345e-8 has 12 decimals.
1.2345e-08 has 12 decimals.
π has 15 decimals.
```

## Kotlin

Translation of: Java
`fun findNumOfDec(x: Double): Int {    val str = x.toString()    if (str.endsWith(".0")) {        return 0    }    return str.substring(str.indexOf('.')).length - 1} fun main() {    for (n in listOf(12.0, 12.345, 12.345555555555, 12.3450, 12.34555555555555555555, 1.2345e+54)) {        println("%f has %d decimals".format(n, findNumOfDec(n)))    }}`
Output:
```12.000000 has 0 decimals
12.345000 has 3 decimals
12.345556 has 12 decimals
12.345000 has 3 decimals
12.345556 has 15 decimals
1234500000000000000000000000000000000000000000000000000.000000 has 7 decimals```

## Lambdatalk

In lambdatalk numbers are words/strings, some operators, like "+,-,*,/,...", know what to do with words like "123".

A first answer could be

` {W.length  {S.rest      {S.replace \. by space in 12.3450}}}-> 4                    `

This is a better one, if considering that ending zeroes should not be considered as decimals

` {def decimals {def decimals.r  {lambda {:w}   {if {= {W.first :w} 0}    then {decimals.r {W.rest :w}}    else :w}}} {lambda {:w}  {W.length   {decimals.r    {S.first     {W.reverse      {S.replace \. by space in :w}}}}}}}-> decimals {decimals 12.34560001230000}-> 10 `

Numbers can be of any size.

## Perl

Need pragma `bignum` to handle decimals beyond 15 digits.

`use bignum; printf "Fractional precision: %2s  Number: %s\n", length((split /\./, \$_)[1]) // 0, \$_    for 9, 12.345, <12.3450>, 0.1234567890987654321, 1/3, 1.5**63;`
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: 40  Number: 0.3333333333333333333333333333333333333333
Fractional precision: 63  Number: 124093581919.648947697827373650380188008224280338254175148904323577880859375```

## Phix

```constant fracfmt = iff(machine_bits()=32?"%.14g":"%.18g")

function num_decimals(object o)
integer nd = -1
string s, t
if integer(o) then
nd = 0
s = sprintf("%d",o)
elsif atom(o) then
s = sprintf("%.19g",o)
o -= trunc(o)
if o=0 then
nd = 0
else
t = sprintf(fracfmt,o)
end if
elsif string(o) then
s = o
t = s
else
crash("unknown type")
end if
if nd=-1 then
integer e = find('e',t)
if e then
{t,e} = {t[1..e-1],to_number(t[e+1..\$])}
end if
integer dot = find('.',t)
nd = iff(dot?max(length(t)-dot-e,0):max(-e,0))
end if
s = shorten(s,"digits",5)
return {s,nd}
end function

sequence tests = {"0.00100", 0.00100, 001.805, 1/3, 12, 12.345, 12.345555555555,
"12.3450", "12.34555555555555555555", 12.345e53, 1.2345e-08,
"12.345e53", "1.2345e-08", "0.1234567890987654321",
"124093581919.648947697827373650380188008224280338254175148904323577880859375"}

for i=1 to length(tests) do
printf(1,"%25s has %d decimals\n",num_decimals(tests[i]))
end for
```
Output:

32 bit

```                  0.00100 has 5 decimals
0.001 has 3 decimals
1.805 has 3 decimals
0.3333333333333333 has 14 decimals
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
1.2345e-8 has 12 decimals
12.345e53 has 0 decimals
1.2345e-08 has 12 decimals
0.1234567890987654321 has 19 decimals
12409...59375 (76 digits) has 63 decimals
```

64 bit as above except

```    0.3333333333333333333 has 18 decimals
```

## Python

Treated as a function over a string representation of a number to allow the capturing of significant trailing zeros.

`In [6]: def dec(n):   ...:     return len(n.rsplit('.')[-1]) if '.' in n else 0 In [7]: dec('12.345')Out[7]: 3 In [8]: dec('12.3450')Out[8]: 4 In [9]: `

Or, defining a slightly less partial function, over a given number, rather than a string:

`'''Report the decimal counts in default stringifications.''' import math  # decimalCount :: Num -> Either String (Int, Int)def decimalCount(n):    '''Either a message string, or a tuple       giving the number of decimals in the default       (repr) representations of the real       (and any imaginary part) of the given number.    '''    # decimalLen :: Float -> Int    def decimalLen(f):        return len(repr(f).split('.')[-1])     return Right(        (0, 0) if isinstance(n, int) else (            (decimalLen(n), 0)        ) if isinstance(n, float) else (            tuple(decimalLen(x) for x in [n.real, n.imag])        )    ) if isinstance(n, (float, complex, int)) else (        Left(repr(n) + ' is not a float, complex or int')    )  # -------------------------- TEST --------------------------# main :: IO ()def main():    '''Counts of decimals in default stringifications of       real (and any imaginary) components of various       Python numeric values.    '''    print(fTable(        'Decimal counts in stringifications of real and imaginary components:'    )(repr)(        either(identity)(repr)    )(decimalCount)([        7, 1.25, 1.23456e2,        1 / 7,        2 ** 0.5,        math.pi, math.e,        complex(1.23, 4.567),        None    ]))  # ------------------------ GENERIC ------------------------- # Left :: a -> Either a bdef Left(x):    '''Constructor for an empty Either (option type) value       with an associated string.    '''    return {'type': 'Either', 'Right': None, 'Left': x}  # Right :: b -> Either a bdef Right(x):    '''Constructor for a populated Either (option type) value'''    return {'type': 'Either', 'Left': None, 'Right': x}  # either :: (a -> c) -> (b -> c) -> Either a b -> cdef either(fl):    '''The application of fl to e if e is a Left value,       or the application of fr to e if e is a Right value.    '''    return lambda fr: lambda e: fl(e['Left']) if (        None is e['Right']    ) else fr(e['Right'])  # identity :: a -> adef identity(x):    '''The identity function.'''    return x  # ------------------------ DISPLAY ------------------------- # fTable :: String -> (a -> String) -># (b -> String) -> (a -> b) -> [a] -> Stringdef fTable(s):    '''Heading -> x display function -> fx display function ->       f -> xs -> tabular string.    '''    def gox(xShow):        def gofx(fxShow):            def gof(f):                def goxs(xs):                    ys = [xShow(x) for x in xs]                    w = max(map(len, ys))                     def arrowed(x, y):                        return y.rjust(w, ' ') + ' -> ' + fxShow(f(x))                    return s + '\n' + '\n'.join(                        map(arrowed, xs, ys)                    )                return goxs            return gof        return gofx    return gox  # MAIN ---if __name__ == '__main__':    main()`
Output:
```Decimal counts in stringifications of real and imaginary components:
7 -> (0, 0)
1.25 -> (2, 0)
123.456 -> (3, 0)
0.14285714285714285 -> (17, 0)
1.4142135623730951 -> (16, 0)
3.141592653589793 -> (15, 0)
2.718281828459045 -> (15, 0)
(1.23+4.567j) -> (2, 3)
None -> None is not a float, complex or int```

## Raku

Works with: Rakudo version 2020.07

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.)

`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; `
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```

## REXX

Since the REXX language stores numbers as strings,   the issue of trailing zeros is a moot point.
If the number (as specified) has trailing zeros, there are left intact.

I took it to mean that the number of decimal digits   past the decimal point   are to be counted and displayed.

Any number specified in exponential notation is first converted to a whole or fractional integer   (or an integer with scale),
and  that  number is then examined.

`/*REXX pgm counts number of decimal digits which are to the right of the decimal point. */numeric digits 1000                              /*ensure enuf dec digs for calculations*/@.=;                                             /*initialize a stemmed array to nulls. */parse arg @.1;  if @.1=''  then do;      #= 9    /*#:  is the number of default numbers.*/                                @.1 = 12                                @.2 = 12.345                                @.3 = 12.345555555555                                @.4 = 12.3450                                @.5 = 12.34555555555555555555                                @.6 = 1.2345e+54                                @.7 = 1.2345e-54                                @.8 = 0.1234567890987654321                                @.9 = 1.5 ** 63  /*calculate  1.5  raised to 63rd power.*/                                end                           else #= 1             /*the # of numbers specified on the CL.*/ say 'fractional'say ' decimals '  center("number", 75)say '══════════'  copies("═", 75)           do j=1  for #;    n= countDec(@.j)     /*obtain the number of fractional digs.*/          say right(n, 5)   left('',4)  @.j      /*show # of fract. digits & original #.*/          end   /*j*/exit 0                                           /*stick a fork in it,  we're all done. *//*──────────────────────────────────────────────────────────────────────────────────────*/countDec: procedure; parse upper arg x           /*obtain a number from the invoker.    */          if pos('E', x)>0  then do              /*handle if the number has an exponent.*/                                 LX= length(x)           /*length of the original number*/                                 parse var x 'E' expon   /*obtain the exponent.         */                                 LE= length(LE)          /*the length of the exponent.  */                                 numeric digits LX + LE  /*ensure enough decimal digits.*/                                 x= format(x, , , 0)     /*REXX does the heavy lifting. */                                 end          parse var x '.' fract                  /*parse number, get the fractional part*/          return length(fract)                   /*return number of fractional digits.  */`
output   when using the default inputs:
```fractional
decimals                                    number
══════════ ═══════════════════════════════════════════════════════════════════════════
0      12
3      12.345
12      12.345555555555
4      12.3450
20      12.34555555555555555555
0      1.2345E+54
58      1.2345E-54
19      0.1234567890987654321
63      124093581919.648947697827373650380188008224280338254175148904323577880859375
```

## 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 `
Output:
```4
```

## Sidef

`func number_of_decimals(n, limit = 1e5) {    var prec = Num(Num!PREC)>>2    var prev = ''     n = Number(n) if !n.kind_of(Number)     loop {        var str = n.as_dec(prec)         if (prev == str) {            return (str.contains('.') ? str.substr(str.index('.')+1).len : 0)        }         prev = str        prec *= 2        return Inf if (prec > limit)    }} var list = [    9, 12.345, "12.3450", "12.345e53",    12.34555555555555555555, 0.1234567890987654321,    Num.pi, 1/3, 1.5**63] list.each {|n|    var c = number_of_decimals(n)    say "Number of decimals: #{'%3s' % c}  Number: #{n}"}`
Output:
```Number of decimals:   0  Number: 9
Number of decimals:   3  Number: 12.345
Number of decimals:   3  Number: 12.3450
Number of decimals:   0  Number: 12.345e53
Number of decimals:  20  Number: 12.34555555555555555555
Number of decimals:  19  Number: 0.1234567890987654321
Number of decimals: 188  Number: 3.14159265358979323846264338327950288419716939938
Number of decimals: Inf  Number: 0.333333333333333333333333333333333333333333333333
Number of decimals:  63  Number: 124093581919.6489476978273736503801880082242803382541751489
```

## 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.

`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")}`
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
```