Getting the number of decimal places: Difference between revisions
(→{{header|Python}}: Added a slightly less partial variant.) |
(Added various BASIC dialects (True BASIC256 and Run BASIC)) |
||
(54 intermediate revisions by 27 users not shown) | |||
Line 1: | Line 1: | ||
{{draft task}} |
{{draft task}} |
||
;Task: |
|||
Write a program (function) to get the number of decimal places in a given number. |
|||
Write a program (function) to get the number of decimals in a given number. |
|||
Examples: |
;Examples: |
||
:* for num = 12.345 decimals = 3, and |
|||
:* for num = 12.3450 decimals = 4 |
|||
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). |
|||
<br><br> |
|||
=={{header|11l}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="11l">F dec(n) |
|||
R I ‘.’ C n {n.split(‘.’).last.len} E 0 |
|||
print(dec(‘12.345’)) |
|||
print(dec(‘12.3450’))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
3 |
|||
4 |
|||
</pre> |
|||
=={{header|Action!}}== |
|||
{{libheader|Action! Tool Kit}} |
|||
<syntaxhighlight lang="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 |
|||
OD |
|||
RETURN (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 |
|||
FI |
|||
RETURN (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</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Getting_the_number_of_decimals.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|Ada}}== |
|||
<syntaxhighlight lang="ada"> |
|||
-- Report the number of decimal places in a number |
|||
-- J. Carter 2023 Apr |
|||
-- I presume the input is a String containing the image of the value; the test values of 12.345 & 12.3450 represent the same number, |
|||
-- and so would give the same result otherwise |
|||
with Ada.Strings.Fixed; |
|||
with Ada.Text_IO; |
|||
procedure Decimal_Places is |
|||
function Num_Places (Number : in String) return Natural; |
|||
-- Returns the number of decimal places in the numeric image in Number |
|||
function Num_Places (Number : in String) return Natural is |
|||
Dot : constant Natural := Ada.Strings.Fixed.Index (Number, "."); |
|||
begin -- Num_Places |
|||
if Dot = 0 then |
|||
return 0; |
|||
end if; |
|||
return Number'Last - Dot; |
|||
end Num_Places; |
|||
Test_1 : constant String := "12.345"; |
|||
Test_2 : constant String := "12.3450"; |
|||
begin -- Decimal_Places |
|||
Ada.Text_IO.Put_Line (Item => Test_1 & (1 .. 10 - Test_1'Length => ' ') & Num_Places (Test_1)'Image); |
|||
Ada.Text_IO.Put_Line (Item => Test_2 & (1 .. 10 - Test_2'Length => ' ') & Num_Places (Test_2)'Image); |
|||
end Decimal_Places; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
12.345 3 |
|||
12.3450 4 |
|||
</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="arturo">nofDecimals: function [n][ |
|||
str: (string? n)? -> n -> to :string n |
|||
size last split.by:"." str |
|||
] |
|||
loop [12 12.345 "12.3450" 12.34567] 'n -> |
|||
print ["number of decimals of" n "->" nofDecimals n]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>number of decimals of 12 -> 2 |
|||
number of decimals of 12.345 -> 3 |
|||
number of decimals of 12.3450 -> 4 |
|||
number of decimals of 12.34567 -> 5</pre> |
|||
=={{header|AutoHotkey}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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.</pre> |
|||
=={{header|AWK}}== |
|||
<syntaxhighlight lang="awk"> |
|||
# syntax: GAWK -f GETTING_THE_NUMBER_OF_DECIMALS.AWK |
|||
BEGIN { |
|||
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) |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
10 has 0 decimals |
|||
1. has 0 decimals |
|||
1.0 has 1 decimals |
|||
12.345 has 3 decimals |
|||
12.3450 has 4 decimals |
|||
</pre> |
|||
=={{header|BASIC}}== |
|||
==={{header|BASIC256}}=== |
|||
{{trans|FreeBASIC}} |
|||
<syntaxhighlight lang="vbnet">arraybase 1 |
|||
dim n[5] |
|||
n[1] = 7 |
|||
n[2] = 12.00 |
|||
n[3] = 12.345 |
|||
n[4] = 12.345677 |
|||
n[5] = 0.142857142857142 |
|||
for i = n[?,] to n[?] |
|||
print n[i] + " has " + dec(n[i]) + " decimals" |
|||
next i |
|||
end |
|||
function dec(n) |
|||
c = string(n) |
|||
if instr(c, ".") then return length(mid(c, instr(c, ".") + 1, length(c))) else return 0 |
|||
end function</syntaxhighlight> |
|||
{{out}} |
|||
<pre>7 has 0 decimals |
|||
12.0 has 1 decimals |
|||
12.345 has 3 decimals |
|||
12.345677 has 6 decimals |
|||
0.14285714286 has 11 decimals</pre> |
|||
==={{header|Chipmunk Basic}}=== |
|||
{{trans|Yabasic}} |
|||
{{works with|Chipmunk Basic|3.6.4}} |
|||
<syntaxhighlight lang="vbnet">100 dim n(4) |
|||
110 data 7,12,12.345,12.345677,0.142857 |
|||
120 for i = 0 to 4 |
|||
130 read n(i) |
|||
140 print n(i);" has ";dek(n(i));" decimals" |
|||
150 next i |
|||
160 end |
|||
170 sub dek(n) |
|||
180 c$ = str$(n) |
|||
190 if instr(c$,".") then dek = len(mid$(c$,instr(c$,".")+1)) else dek = 0 |
|||
200 end sub</syntaxhighlight> |
|||
==={{header|FreeBASIC}}=== |
|||
<syntaxhighlight lang="vbnet">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 i |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 7 has 0 decimals |
|||
12 has 0 decimals |
|||
12.345 has 3 decimals |
|||
12.345677 has 6 decimals |
|||
0.142857142857142 has 15 decimals</pre> |
|||
==={{header|GW-BASIC}}=== |
|||
The [[#MSX Basic|MSX Basic]] solution works without any changes. |
|||
==={{header|MSX Basic}}=== |
|||
{{works with|MSX BASIC|any}} |
|||
{{works with|Chipmunk Basic}} |
|||
{{works with|GW-BASIC}} |
|||
{{works with|QBasic}} |
|||
{{works with|QB64}} |
|||
<syntaxhighlight lang="qbasic">100 DIM N(4) |
|||
110 DATA 7,12,12.345,12.345677,0.142857 |
|||
120 FOR I = 0 TO 4 |
|||
130 READ N(I) |
|||
140 GOSUB 180 |
|||
150 PRINT N(I);"has";DEC;"decimals" |
|||
160 NEXT I |
|||
170 END |
|||
180 'sub dec(n) |
|||
190 C$ = STR$(N(I)) |
|||
200 IF INSTR(C$,".") <> 0 THEN DEC = LEN(MID$(C$,INSTR(C$,".")+1)) ELSE DEC = 0 |
|||
210 RETURN</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 7 has 0 decimals |
|||
12 has 0 decimals |
|||
12.345 has 3 decimals |
|||
12.34568 has 5 decimals |
|||
.142857 has 6 decimals</pre> |
|||
==={{header|QBasic}}=== |
|||
{{works with|QBasic|1.1}} |
|||
{{works with|QuickBasic|4.5}} |
|||
<syntaxhighlight lang="qbasic">DECLARE FUNCTION dec! (n!) |
|||
DIM n(4) |
|||
DATA 7,12.00,12.345,12.345677,0.142857142857142 |
|||
FOR i = LBOUND(n) TO UBOUND(n) |
|||
READ n(i) |
|||
PRINT n(i); "has"; dec(n(i)); "decimals" |
|||
NEXT i |
|||
END |
|||
FUNCTION dec (n) |
|||
c$ = STR$(n) |
|||
IF INSTR(c$, ".") THEN dec = LEN(MID$(c$, INSTR(c$, ".") + 1)) ELSE dec = 0 |
|||
END FUNCTION</syntaxhighlight> |
|||
==={{header|QB64}}=== |
|||
{{works with|QBasic}} |
|||
<syntaxhighlight lang="vbnet">Dim n(4) |
|||
Data 7,12.00,12.345,12.345677,0.142857142857142 |
|||
For i = LBound(n) To UBound(n) |
|||
Read n(i) |
|||
Print n(i); "has"; dec(n(i)); "decimals" |
|||
Next i |
|||
End |
|||
Function dec (n) |
|||
c$ = Str$(n) |
|||
If InStr(c$, ".") Then dec = Len(Mid$(c$, InStr(c$, ".") + 1)) Else dec = 0 |
|||
End Function</syntaxhighlight> |
|||
==={{header|Run BASIC}}=== |
|||
{{trans|Yabasic}} |
|||
{{works with|Just BASIC}} |
|||
{{works with|Liberty BASIC}} |
|||
<syntaxhighlight lang="vb">dim n(4) |
|||
n(0) = 7 |
|||
n(1) = 12.00 |
|||
n(2) = 12.345 |
|||
n(3) = 12.345677 |
|||
n(4) = 0.142857142857142 |
|||
for i = 0 to 4 |
|||
print n(i); " has "; dek(n(i)); " decimals" |
|||
next i |
|||
end |
|||
function dek(n) |
|||
c$ = str$(n) |
|||
if instr(c$, ".") then dek = len(mid$(c$, instr(c$, ".") + 1)) else dek = 0 |
|||
end function</syntaxhighlight> |
|||
==={{header|True BASIC}}=== |
|||
{{trans|QBasic}} |
|||
<syntaxhighlight lang="qbasic">FUNCTION dec(n_t) |
|||
LET c$ = STR$(n_t) |
|||
IF POS(c$,".")<>0 THEN LET dec = LEN((c$)[POS(c$,".")+1:maxnum]) ELSE LET dec = 0 |
|||
END FUNCTION |
|||
DIM n(5) |
|||
DATA 7, 12.00, 12.345, 12.345677, 0.142857142857142 |
|||
FOR i = LBOUND(n) TO UBOUND(n) |
|||
READ n(i) |
|||
PRINT n(i); "has"; dec(n(i)); "decimals" |
|||
NEXT i |
|||
END</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as QBasic entry.</pre> |
|||
==={{header|Yabasic}}=== |
|||
{{trans|FreeBASIC}} |
|||
<syntaxhighlight lang="vb">dim n(4) |
|||
data 7,12.00,12.345,12.345677,0.142857142857142 |
|||
for i = 0 to 4 |
|||
read n(i) |
|||
print n(i), " has ", dek(n(i)), " decimals" |
|||
next i |
|||
end |
|||
sub dek(n) |
|||
c$ = str$(n) |
|||
if instr(c$, ".") then return len(mid$(c$, instr(c$, ".") + 1)) else return 0: fi |
|||
end sub</syntaxhighlight> |
|||
{{out}} |
|||
<pre>7 has 0 decimals |
|||
12 has 0 decimals |
|||
12.345 has 3 decimals |
|||
12.3457 has 4 decimals |
|||
0.142857 has 6 decimals</pre> |
|||
=={{header|C}}== |
|||
<syntaxhighlight lang="c">#include <stdio.h> |
|||
#include <string.h> |
|||
int findNumOfDec(const char *s) { |
|||
int pos = 0; |
|||
while (s[pos] && s[pos++] != '.') {} |
|||
return strlen(s + pos); |
|||
} |
|||
void test(const char *s) { |
|||
int num = findNumOfDec(s); |
|||
const char *p = num != 1 ? "s" : ""; |
|||
printf("%s has %d decimal%s\n", s, num, p); |
|||
} |
|||
int main() { |
|||
test("12"); |
|||
test("12.0"); |
|||
test("12.345"); |
|||
test("12.345555555555"); |
|||
test("12.3450"); |
|||
test("12.34555555555555555555"); |
|||
char str[64]; |
|||
sprintf(str, "%f", 1.2345e+54); |
|||
test(str); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
12 has 0 decimals |
|||
12.0 has 1 decimal |
|||
12.345 has 3 decimals |
|||
12.345555555555 has 12 decimals |
|||
12.3450 has 4 decimals |
|||
12.34555555555555555555 has 20 decimals |
|||
1234500000000000060751116919315055127939946206157864960.000000 has 6 decimals |
|||
</pre> |
|||
=={{header|C++}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="cpp">#include <iostream> |
|||
#include <cstring> |
|||
int findNumOfDec(const char *s) { |
|||
int pos = 0; |
|||
while (s[pos] && s[pos++] != '.') {} |
|||
return strlen(s + pos); |
|||
} |
|||
void test(const char *s) { |
|||
int num = findNumOfDec(s); |
|||
const char *p = num != 1 ? "s" : ""; |
|||
std::cout << s << " has " << num << " decimal" << p << "\n"; |
|||
} |
|||
int main() { |
|||
test("12"); |
|||
test("12.0"); |
|||
test("12.345"); |
|||
test("12.345555555555"); |
|||
test("12.3450"); |
|||
test("12.34555555555555555555"); |
|||
char str[64]; |
|||
sprintf(str, "%f", 1.2345e+54); |
|||
test(str); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
12 has 0 decimals |
|||
12.0 has 1 decimal |
|||
12.345 has 3 decimals |
|||
12.345555555555 has 12 decimals |
|||
12.3450 has 4 decimals |
|||
12.34555555555555555555 has 20 decimals |
|||
1234500000000000060751116919315055127939946206157864960.000000 has 6 decimals |
|||
</pre> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight> |
|||
func ndec n . |
|||
while abs (n - floor (n + 1e-15)) > 1e-15 |
|||
n *= 10 |
|||
r += 1 |
|||
. |
|||
return r |
|||
. |
|||
for i in [ 0.00000000000001 12.345 12.3450 1.1 0.1234567 ] |
|||
write ndec i & " " |
|||
. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
14 3 3 1 7 |
|||
</pre> |
|||
=={{header|F_Sharp|F#}}== |
|||
<syntaxhighlight lang="fsharp"> |
|||
//Getting the number of decimal places. Nigel Galloway: March 23rd., 2023. |
|||
let fN g=let n,g=Seq.length g,g|>Seq.tryFindIndex((=)'.') in match g with Some g->n-g-1 |_->0 |
|||
["12";"12.00";"12.345";"12.3450";"12.34500"]|>List.iter(fN>>printfn "%d") |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
0 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
{{trans|Wren}} |
{{trans|Wren}} |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 76: | Line 559: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 87: | Line 570: | ||
1.2345e+54 has 0 decimals |
1.2345e+54 has 0 decimals |
||
</pre> |
</pre> |
||
=={{Header|Haskell}}== |
|||
<syntaxhighlight lang="haskell">decimal :: String -> Int |
|||
decimal [] = 0 |
|||
decimal ('.':xs) = length xs |
|||
decimal (_:xs) = decimal xs |
|||
numDecimal :: Double -> Int |
|||
numDecimal = decimal . show |
|||
main = print . map numDecimal $ [12.0, 12.345, 12.3450, 12.345555555555, 12.34555555555555555555, 1.2345e+54]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[1,3,3,12,15,7]</pre> |
|||
=={{header|Java}}== |
|||
<syntaxhighlight lang="java"> |
|||
int decimalPlaces(double value) { |
|||
String string = String.valueOf(value); |
|||
return string.length() - (string.indexOf('.') + 1); |
|||
} |
|||
</syntaxhighlight> |
|||
Or |
|||
<syntaxhighlight lang="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); |
|||
}</syntaxhighlight> |
|||
=={{header|jq}}== |
|||
The current (March 2023) official releases of jq, gojq, fq, and jaq cannot be relied upon |
|||
to preserve the literal form of numbers, and in particular they drop the |
|||
final 0 of `12.3450` when presented as a number. However, the current "master" version of jq retains |
|||
the literal form of numbers. Accordingly, both the numeric and the string forms of 12.3450 are included in the suite of test |
|||
cases, and two sets of results are presented below. |
|||
<syntaxhighlight lang=jq> |
|||
def number_decimal_digits: |
|||
. as $in |
|||
| def nil: . == null or . == ""; |
|||
def nodecimal: # e.g. 12 or 12e-2 |
|||
capture("^[-+]?[0-9]*([eE](?<sign>[-+]?)(?<p>[0-9]+))?$") |
|||
| if .sign|nil then 0 |
|||
elif .p|nil then "internal error: \($in)"|error |
|||
else .p|tonumber |
|||
end; |
|||
tostring |
|||
| nodecimal |
|||
// capture("^[-+]?[0-9]*[.](?<d>[0-9]+)([eE](?<sign>[-+]?)(?<p>[0-9]+))?$") # has decimal |
|||
// null |
|||
| if type == "number" then . |
|||
elif not then 0 |
|||
elif .d|nil then 0 |
|||
elif (.sign|nil) and .p == null then .d|length |
|||
elif (.sign|nil) or .sign == "+" then [0, (.d|length) - (.p|tonumber)] | max |
|||
elif .sign == "-" then (.d|length) + (.p|tonumber) |
|||
else "internal error: \($in)"|error |
|||
end ; |
|||
def examples: |
|||
[12.345, 3], |
|||
[12.3450, 4], |
|||
["12.3450", 4], |
|||
[1e-2, 2], |
|||
[1.23e2, 0]; |
|||
def task: |
|||
examples |
|||
| (first|number_decimal_digits) as $d |
|||
| if $d == last then empty |
|||
else "\(first) has \(last) decimal places but the computed value is \($d)" |
|||
end; |
|||
task, "Bye." |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
Using gojq: |
|||
<pre> |
|||
12.345 has 4 decimal places but the computed value is 3 |
|||
Bye. |
|||
</pre> |
|||
Using jq post-1.6: |
|||
<pre> |
|||
Bye. |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia">function postprecision(str::String) |
||
s = lowercase(str) |
s = lowercase(str) |
||
if 'e' in s |
if 'e' in s |
||
Line 100: | Line 665: | ||
return dig > 0 ? dig : 0 |
return dig > 0 ? dig : 0 |
||
end |
end |
||
postprecision(x::Integer) = 0 |
postprecision(x::Integer) = 0 |
||
postprecision(x::Real, max=22) = postprecision(string(round(Float64(x), digits=max))) |
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", |
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] |
"12.34555555555555555555", 1.2345e+54, 1.2345e-08, "1.2345e-08", π] |
||
for n in testnums |
for n in testnums |
||
println("$n has $(postprecision(n)) decimals.") |
println("$n has $(postprecision(n)) decimals.") |
||
end |
end |
||
</ |
</syntaxhighlight>{{out}} |
||
<pre> |
<pre> |
||
0.00100 has 5 decimals. |
0.00100 has 5 decimals. |
||
Line 116: | Line 681: | ||
1.805 has 3 decimals. |
1.805 has 3 decimals. |
||
0.3333333333333333 has 16 decimals. |
0.3333333333333333 has 16 decimals. |
||
2//3 has 16 decimals. |
|||
12 has 0 decimals. |
12 has 0 decimals. |
||
12.345 has 3 decimals. |
12.345 has 3 decimals. |
||
Line 122: | Line 688: | ||
1.2345e54 has 0 decimals. |
1.2345e54 has 0 decimals. |
||
1.2345e-8 has 12 decimals. |
1.2345e-8 has 12 decimals. |
||
1.2345e-08 has 12 decimals. |
|||
π has 15 decimals. |
|||
</pre> |
</pre> |
||
=={{header| |
=={{header|Kotlin}}== |
||
{{trans|Java}} |
|||
<lang Phix>constant fracfmt = iff(machine_bits()=32?"%.14g":"%.18g") |
|||
<syntaxhighlight lang="scala">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))) |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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</pre> |
|||
=={{header|Lambdatalk}}== |
|||
In lambdatalk numbers are words/strings, some operators, like "+,-,*,/,...", know what to do with words like "123". |
|||
A first answer could be |
|||
<syntaxhighlight lang="scheme"> |
|||
{W.length |
|||
{S.rest |
|||
{S.replace \. by space in 12.3450}}} |
|||
-> 4 |
|||
</syntaxhighlight> |
|||
This is a better one, if considering that ending zeroes should not be considered as decimals |
|||
<syntaxhighlight lang="schema"> |
|||
{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 |
|||
</syntaxhighlight> |
|||
Numbers can be of any size. |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">ClearAll[DecimalDigits] |
|||
DecimalDigits[r_String] := Module[{pos}, |
|||
If[StringContainsQ[r, "."], |
|||
pos = StringPosition[r, "."][[-1, 1]]; |
|||
StringLength[StringDrop[r, pos]] |
|||
, |
|||
0 |
|||
] |
|||
] |
|||
DecimalDigits["12.345"] |
|||
DecimalDigits["12.3450"] |
|||
DecimalDigits["8"] |
|||
DecimalDigits["3128"] |
|||
DecimalDigits["13."] |
|||
DecimalDigits["13.1312312"]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>3 |
|||
4 |
|||
0 |
|||
0 |
|||
0 |
|||
7</pre> |
|||
=={{header|Perl}}== |
|||
Need pragma <code>bignum</code> to handle decimals beyond 15 digits. |
|||
<syntaxhighlight lang="perl">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;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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</pre> |
|||
=={{header|Phix}}== |
|||
<!--(phixonline)--> |
|||
<syntaxhighlight lang="phix"> |
|||
constant fracfmt = iff(machine_bits()=32?"%.14g":"%.18g") |
|||
function num_decimals(object o) |
function num_decimals(object o) |
||
integer nd = -1 |
integer nd = -1 |
||
Line 153: | Line 818: | ||
end if |
end if |
||
integer dot = find('.',t) |
integer dot = find('.',t) |
||
nd = iff(dot?max(length(t)-dot-e,0):0) |
nd = iff(dot?max(length(t)-dot-e,0):max(-e,0)) |
||
end if |
end if |
||
s = shorten(s, |
s = shorten(s,"digits",5) |
||
return {s,nd} |
return {s,nd} |
||
end function |
end function |
||
Line 163: | Line 828: | ||
"12.345e53", "1.2345e-08", "0.1234567890987654321", |
"12.345e53", "1.2345e-08", "0.1234567890987654321", |
||
"124093581919.648947697827373650380188008224280338254175148904323577880859375"} |
"124093581919.648947697827373650380188008224280338254175148904323577880859375"} |
||
for i=1 to length(tests) do |
for i=1 to length(tests) do |
||
printf(1,"%25s has %d decimals\n",num_decimals(tests[i])) |
printf(1,"%25s has %d decimals\n",num_decimals(tests[i])) |
||
end for |
end for |
||
</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
32 bit |
32 bit |
||
Line 192: | Line 858: | ||
=={{header|Python}}== |
=={{header|Python}}== |
||
Treated as a function over a string representation of a number to allow the capturing of significant trailing zeros. |
|||
( Though this fails with an error when the given number is math.e, math.pi, or math.tau, for example, all presumably 'numbers', and certainly Python '''float''' values) |
|||
< |
<syntaxhighlight lang="python">In [6]: def dec(n): |
||
...: return len(n.rsplit('.')[-1]) if '.' in n else 0 |
...: return len(n.rsplit('.')[-1]) if '.' in n else 0 |
||
Line 202: | Line 868: | ||
Out[8]: 4 |
Out[8]: 4 |
||
In [9]: </ |
In [9]: </syntaxhighlight> |
||
Or, defining a slightly less partial function: |
Or, defining a slightly less partial function, over a given number, rather than a string: |
||
< |
<syntaxhighlight lang="python">'''Report the decimal counts in default stringifications.''' |
||
import math |
import math |
||
Line 215: | Line 881: | ||
def decimalCount(n): |
def decimalCount(n): |
||
'''Either a message string, or a tuple |
'''Either a message string, or a tuple |
||
giving the number of decimals in the |
giving the number of decimals in the default |
||
(repr) representations of the real |
|||
(and any imaginary part) of the given number. |
(and any imaginary part) of the given number. |
||
''' |
''' |
||
Line 278: | Line 945: | ||
None is e['Right'] |
None is e['Right'] |
||
) else fr(e['Right']) |
) else fr(e['Right']) |
||
# identity :: a -> a |
# identity :: a -> a |
||
Line 283: | Line 951: | ||
'''The identity function.''' |
'''The identity function.''' |
||
return x |
return x |
||
# ------------------------ DISPLAY ------------------------- |
# ------------------------ DISPLAY ------------------------- |
||
Line 312: | Line 981: | ||
# MAIN --- |
# MAIN --- |
||
if __name__ == '__main__': |
if __name__ == '__main__': |
||
main()</ |
main()</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>Decimal counts in stringifications of real and imaginary components: |
<pre>Decimal counts in stringifications of real and imaginary components: |
||
Line 337: | Line 1,006: | ||
want to retain them, you need to pass the value as a string. (As below.) |
want to retain them, you need to pass the value as a string. (As below.) |
||
<lang |
<syntaxhighlight lang="raku" line>use Rat::Precise; |
||
printf "Fractional precision: %-2s || Number: %s\n", (.split('.')[1] // '').chars, $_ |
printf "Fractional precision: %-2s || Number: %s\n", (.split('.')[1] // '').chars, $_ |
||
for 9, 12.345, '12.3450', 0.1234567890987654321, (1.5**63).precise; |
for 9, 12.345, '12.3450', 0.1234567890987654321, (1.5**63).precise; |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>Fractional precision: 0 || Number: 9 |
<pre>Fractional precision: 0 || Number: 9 |
||
Line 351: | Line 1,020: | ||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Since the REXX language stores numbers as strings, the issue of trailing zeros is a moot point. |
|||
<br>If the number (as specified) has trailing zeros, there are left intact. |
|||
I took it to mean that the number of decimal digits <u>past the decimal point</u> 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), <br>and that number is then examined. |
|||
<syntaxhighlight 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*/ |
numeric digits 1000 /*ensure enuf dec digs for calculations*/ |
||
@.=; /*initialize a stemmed array to nulls. */ |
@.=; /*initialize a stemmed array to nulls. */ |
||
Line 385: | Line 1,061: | ||
end |
end |
||
parse var x '.' fract /*parse number, get the fractional part*/ |
parse var x '.' fract /*parse number, get the fractional part*/ |
||
return length(fract) /*return number of fractional digits. */</ |
return length(fract) /*return number of fractional digits. */</syntaxhighlight> |
||
{{out|output|text= when using the default inputs:}} |
{{out|output|text= when using the default inputs:}} |
||
<pre> |
<pre> |
||
Line 403: | Line 1,079: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
# Testing the function |
# Testing the function |
||
decimals(2) # Unsensitive to the default setting of decimals |
decimals(2) # Unsensitive to the default setting of decimals |
||
Line 424: | Line 1,100: | ||
ok |
ok |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
4 |
4 |
||
</pre> |
|||
'''Another version''' |
|||
<syntaxhighlight lang="ring"> |
|||
decimals(4) |
|||
num = 5.1945 |
|||
strnum = string(num) |
|||
pos = substr(strnum,".") |
|||
dec = len(strnum) - pos |
|||
see "Number of decimals: " + dec + nl |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Number of decimals: 4 |
|||
</pre> |
|||
=={{header|RPL}}== |
|||
≪ DUP MANT →STR SIZE SWAP XPON - 2 - 0 MAX |
|||
≫ ''''NDEC'''' STO |
|||
≪ { 12 120 12.345 12.345677 1.23E-20 1.23E20 } → cases |
|||
≪ { } 1 cases SIZE '''FOR''' j |
|||
cases j GET '''NDEC''' + '''NEXT''' |
|||
≫ ≫ ''''TASK'''' STO |
|||
{{out}} |
|||
<pre> |
|||
1: { 0 0 3 6 22 0 } |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby">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}" |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
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 |
|||
</pre> |
</pre> |
||
Line 434: | Line 1,181: | ||
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. |
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. |
||
< |
<syntaxhighlight lang="wren">var error = "Argument must be a number or a decimal numeric string." |
||
var getNumDecimals = Fn.new { |n| |
var getNumDecimals = Fn.new { |n| |
||
Line 457: | Line 1,204: | ||
var ns = (n is String) ? "\"%(n)\"" : "%(n)" |
var ns = (n is String) ? "\"%(n)\"" : "%(n)" |
||
System.print("%(ns) has %(d) decimals") |
System.print("%(ns) has %(d) decimals") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
Latest revision as of 21:40, 9 June 2024
Write a program (function) to get the number of decimal places in a given number.
- Task
- 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
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
OD
RETURN (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
FI
RETURN (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:
Screenshot from Atari 8-bit computer
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
Ada
-- Report the number of decimal places in a number
-- J. Carter 2023 Apr
-- I presume the input is a String containing the image of the value; the test values of 12.345 & 12.3450 represent the same number,
-- and so would give the same result otherwise
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure Decimal_Places is
function Num_Places (Number : in String) return Natural;
-- Returns the number of decimal places in the numeric image in Number
function Num_Places (Number : in String) return Natural is
Dot : constant Natural := Ada.Strings.Fixed.Index (Number, ".");
begin -- Num_Places
if Dot = 0 then
return 0;
end if;
return Number'Last - Dot;
end Num_Places;
Test_1 : constant String := "12.345";
Test_2 : constant String := "12.3450";
begin -- Decimal_Places
Ada.Text_IO.Put_Line (Item => Test_1 & (1 .. 10 - Test_1'Length => ' ') & Num_Places (Test_1)'Image);
Ada.Text_IO.Put_Line (Item => Test_2 & (1 .. 10 - Test_2'Length => ' ') & Num_Places (Test_2)'Image);
end Decimal_Places;
- Output:
12.345 3 12.3450 4
Arturo
nofDecimals: function [n][
str: (string? n)? -> n -> to :string n
size last split.by:"." str
]
loop [12 12.345 "12.3450" 12.34567] 'n ->
print ["number of decimals of" n "->" nofDecimals n]
- Output:
number of decimals of 12 -> 2 number of decimals of 12.345 -> 3 number of decimals of 12.3450 -> 4 number of decimals of 12.34567 -> 5
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.AWK
BEGIN {
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
BASIC
BASIC256
arraybase 1
dim n[5]
n[1] = 7
n[2] = 12.00
n[3] = 12.345
n[4] = 12.345677
n[5] = 0.142857142857142
for i = n[?,] to n[?]
print n[i] + " has " + dec(n[i]) + " decimals"
next i
end
function dec(n)
c = string(n)
if instr(c, ".") then return length(mid(c, instr(c, ".") + 1, length(c))) else return 0
end function
- Output:
7 has 0 decimals 12.0 has 1 decimals 12.345 has 3 decimals 12.345677 has 6 decimals 0.14285714286 has 11 decimals
Chipmunk Basic
100 dim n(4)
110 data 7,12,12.345,12.345677,0.142857
120 for i = 0 to 4
130 read n(i)
140 print n(i);" has ";dek(n(i));" decimals"
150 next i
160 end
170 sub dek(n)
180 c$ = str$(n)
190 if instr(c$,".") then dek = len(mid$(c$,instr(c$,".")+1)) else dek = 0
200 end sub
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 i
Sleep
- Output:
7 has 0 decimals 12 has 0 decimals 12.345 has 3 decimals 12.345677 has 6 decimals 0.142857142857142 has 15 decimals
GW-BASIC
The MSX Basic solution works without any changes.
MSX Basic
100 DIM N(4)
110 DATA 7,12,12.345,12.345677,0.142857
120 FOR I = 0 TO 4
130 READ N(I)
140 GOSUB 180
150 PRINT N(I);"has";DEC;"decimals"
160 NEXT I
170 END
180 'sub dec(n)
190 C$ = STR$(N(I))
200 IF INSTR(C$,".") <> 0 THEN DEC = LEN(MID$(C$,INSTR(C$,".")+1)) ELSE DEC = 0
210 RETURN
- Output:
7 has 0 decimals 12 has 0 decimals 12.345 has 3 decimals 12.34568 has 5 decimals .142857 has 6 decimals
QBasic
DECLARE FUNCTION dec! (n!)
DIM n(4)
DATA 7,12.00,12.345,12.345677,0.142857142857142
FOR i = LBOUND(n) TO UBOUND(n)
READ n(i)
PRINT n(i); "has"; dec(n(i)); "decimals"
NEXT i
END
FUNCTION dec (n)
c$ = STR$(n)
IF INSTR(c$, ".") THEN dec = LEN(MID$(c$, INSTR(c$, ".") + 1)) ELSE dec = 0
END FUNCTION
QB64
Dim n(4)
Data 7,12.00,12.345,12.345677,0.142857142857142
For i = LBound(n) To UBound(n)
Read n(i)
Print n(i); "has"; dec(n(i)); "decimals"
Next i
End
Function dec (n)
c$ = Str$(n)
If InStr(c$, ".") Then dec = Len(Mid$(c$, InStr(c$, ".") + 1)) Else dec = 0
End Function
Run BASIC
dim n(4)
n(0) = 7
n(1) = 12.00
n(2) = 12.345
n(3) = 12.345677
n(4) = 0.142857142857142
for i = 0 to 4
print n(i); " has "; dek(n(i)); " decimals"
next i
end
function dek(n)
c$ = str$(n)
if instr(c$, ".") then dek = len(mid$(c$, instr(c$, ".") + 1)) else dek = 0
end function
True BASIC
FUNCTION dec(n_t)
LET c$ = STR$(n_t)
IF POS(c$,".")<>0 THEN LET dec = LEN((c$)[POS(c$,".")+1:maxnum]) ELSE LET dec = 0
END FUNCTION
DIM n(5)
DATA 7, 12.00, 12.345, 12.345677, 0.142857142857142
FOR i = LBOUND(n) TO UBOUND(n)
READ n(i)
PRINT n(i); "has"; dec(n(i)); "decimals"
NEXT i
END
- Output:
Same as QBasic entry.
Yabasic
dim n(4)
data 7,12.00,12.345,12.345677,0.142857142857142
for i = 0 to 4
read n(i)
print n(i), " has ", dek(n(i)), " decimals"
next i
end
sub dek(n)
c$ = str$(n)
if instr(c$, ".") then return len(mid$(c$, instr(c$, ".") + 1)) else return 0: fi
end sub
- Output:
7 has 0 decimals 12 has 0 decimals 12.345 has 3 decimals 12.3457 has 4 decimals 0.142857 has 6 decimals
C
#include <stdio.h>
#include <string.h>
int findNumOfDec(const char *s) {
int pos = 0;
while (s[pos] && s[pos++] != '.') {}
return strlen(s + pos);
}
void test(const char *s) {
int num = findNumOfDec(s);
const char *p = num != 1 ? "s" : "";
printf("%s has %d decimal%s\n", s, num, p);
}
int main() {
test("12");
test("12.0");
test("12.345");
test("12.345555555555");
test("12.3450");
test("12.34555555555555555555");
char str[64];
sprintf(str, "%f", 1.2345e+54);
test(str);
return 0;
}
- Output:
12 has 0 decimals 12.0 has 1 decimal 12.345 has 3 decimals 12.345555555555 has 12 decimals 12.3450 has 4 decimals 12.34555555555555555555 has 20 decimals 1234500000000000060751116919315055127939946206157864960.000000 has 6 decimals
C++
#include <iostream>
#include <cstring>
int findNumOfDec(const char *s) {
int pos = 0;
while (s[pos] && s[pos++] != '.') {}
return strlen(s + pos);
}
void test(const char *s) {
int num = findNumOfDec(s);
const char *p = num != 1 ? "s" : "";
std::cout << s << " has " << num << " decimal" << p << "\n";
}
int main() {
test("12");
test("12.0");
test("12.345");
test("12.345555555555");
test("12.3450");
test("12.34555555555555555555");
char str[64];
sprintf(str, "%f", 1.2345e+54);
test(str);
return 0;
}
- Output:
12 has 0 decimals 12.0 has 1 decimal 12.345 has 3 decimals 12.345555555555 has 12 decimals 12.3450 has 4 decimals 12.34555555555555555555 has 20 decimals 1234500000000000060751116919315055127939946206157864960.000000 has 6 decimals
EasyLang
func ndec n .
while abs (n - floor (n + 1e-15)) > 1e-15
n *= 10
r += 1
.
return r
.
for i in [ 0.00000000000001 12.345 12.3450 1.1 0.1234567 ]
write ndec i & " "
.
- Output:
14 3 3 1 7
F#
//Getting the number of decimal places. Nigel Galloway: March 23rd., 2023.
let fN g=let n,g=Seq.length g,g|>Seq.tryFindIndex((=)'.') in match g with Some g->n-g-1 |_->0
["12";"12.00";"12.345";"12.3450";"12.34500"]|>List.iter(fN>>printfn "%d")
- Output:
0 2 3 4 5
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)
}
}
}
- 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
Haskell
decimal :: String -> Int
decimal [] = 0
decimal ('.':xs) = length xs
decimal (_:xs) = decimal xs
numDecimal :: Double -> Int
numDecimal = 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
int decimalPlaces(double value) {
String string = String.valueOf(value);
return string.length() - (string.indexOf('.') + 1);
}
Or
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);
}
jq
The current (March 2023) official releases of jq, gojq, fq, and jaq cannot be relied upon to preserve the literal form of numbers, and in particular they drop the final 0 of `12.3450` when presented as a number. However, the current "master" version of jq retains the literal form of numbers. Accordingly, both the numeric and the string forms of 12.3450 are included in the suite of test cases, and two sets of results are presented below.
def number_decimal_digits:
. as $in
| def nil: . == null or . == "";
def nodecimal: # e.g. 12 or 12e-2
capture("^[-+]?[0-9]*([eE](?<sign>[-+]?)(?<p>[0-9]+))?$")
| if .sign|nil then 0
elif .p|nil then "internal error: \($in)"|error
else .p|tonumber
end;
tostring
| nodecimal
// capture("^[-+]?[0-9]*[.](?<d>[0-9]+)([eE](?<sign>[-+]?)(?<p>[0-9]+))?$") # has decimal
// null
| if type == "number" then .
elif not then 0
elif .d|nil then 0
elif (.sign|nil) and .p == null then .d|length
elif (.sign|nil) or .sign == "+" then [0, (.d|length) - (.p|tonumber)] | max
elif .sign == "-" then (.d|length) + (.p|tonumber)
else "internal error: \($in)"|error
end ;
def examples:
[12.345, 3],
[12.3450, 4],
["12.3450", 4],
[1e-2, 2],
[1.23e2, 0];
def task:
examples
| (first|number_decimal_digits) as $d
| if $d == last then empty
else "\(first) has \(last) decimal places but the computed value is \($d)"
end;
task, "Bye."
- Output:
Using gojq:
12.345 has 4 decimal places but the computed value is 3 Bye.
Using jq post-1.6:
Bye.
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::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
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.
Mathematica/Wolfram Language
ClearAll[DecimalDigits]
DecimalDigits[r_String] := Module[{pos},
If[StringContainsQ[r, "."],
pos = StringPosition[r, "."][[-1, 1]];
StringLength[StringDrop[r, pos]]
,
0
]
]
DecimalDigits["12.345"]
DecimalDigits["12.3450"]
DecimalDigits["8"]
DecimalDigits["3128"]
DecimalDigits["13."]
DecimalDigits["13.1312312"]
- Output:
3 4 0 0 0 7
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 b
def 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 b
def 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 -> c
def 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 -> a
def identity(x):
'''The identity function.'''
return x
# ------------------------ DISPLAY -------------------------
# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def 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
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
Another version
decimals(4)
num = 5.1945
strnum = string(num)
pos = substr(strnum,".")
dec = len(strnum) - pos
see "Number of decimals: " + dec + nl
- Output:
Number of decimals: 4
RPL
≪ DUP MANT →STR SIZE SWAP XPON - 2 - 0 MAX ≫ 'NDEC' STO ≪ { 12 120 12.345 12.345677 1.23E-20 1.23E20 } → cases ≪ { } 1 cases SIZE FOR j cases j GET NDEC + NEXT ≫ ≫ 'TASK' STO
- Output:
1: { 0 0 3 6 22 0 }
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