Getting the number of decimal places: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: used a calcuation of 1.5^63 instead of the literal (expressed) number.)
(julia example)
Line 86: Line 86:
"12.34555555555555555555" has 20 decimals
"12.34555555555555555555" has 20 decimals
1.2345e+54 has 0 decimals
1.2345e+54 has 0 decimals
</pre>

=={{header|Julia}}==
<lang 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 : 0
end
postprecision(x::Real, max=22) = postprecision(string(round(Float64(x), digits=max)))

testnums = ["0.00100", 0.00100, 001.805, 1.0 / 3, 12, 12.345, "12.3450",
"12.34555555555555555555", 1.2345e+54, 1.2345e-08]

for n in testnums
println("$n has $(postprecision(n)) decimals.")
end
</lang>{{out}}
<pre>
0.00100 has 5 decimals.
0.001 has 3 decimals.
1.805 has 3 decimals.
0.3333333333333333 has 16 decimals.
12 has 1 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.
</pre>
</pre>



Revision as of 00:02, 14 August 2020

Getting the number of decimal places 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




Go

Translation of: Wren

<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

Julia

<lang 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 : 0

end

postprecision(x::Real, max=22) = postprecision(string(round(Float64(x), digits=max)))

testnums = ["0.00100", 0.00100, 001.805, 1.0 / 3, 12, 12.345, "12.3450",

   "12.34555555555555555555", 1.2345e+54, 1.2345e-08]

for n in testnums

   println("$n has $(postprecision(n)) decimals.")

end

</lang>

Output:
0.00100 has 5 decimals.
0.001 has 3 decimals.
1.805 has 3 decimals.
0.3333333333333333 has 16 decimals.
12 has 1 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.

Python

<lang python>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]: </lang>

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

<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


REXX

<lang rexx>/*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.  */</lang>
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

<lang ring>

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