How to count the number of digits of a floating number?

Hello guys,

I am a little confused about the following. I need to get the number of floating digits of a float number. So I have for example the number:

12.345678

And I know that the number of int digits are 2 with the following code:

float a = 12.345678;
void setup()
{
  int u=0;
  while(a/pow(10.0,u)>1)
  {
    u++
  }
  print("nuber of units =",u);
}
void draw()
{
}

but when I want to count the number of decimals, I have witten this code:

void setup()
{
  size(100,100);
  println(numUnits(123.45678));
  println(numDecimals(123.45678, 5));
}

void draw()
{
  
}

int numUnits(float a)
{
  int u=0;
  while(a/(pow(10.0,u))>1)
  {
    u++;
  }
  return u;
}

int numDecimals(float a, int limit)
{
  int d=0;
  float num=0;
  float auxnum=a%numUnits(a);
  float auxnum2=0;
  //println(0-(a-(int)(a))*pow(10.0,1));
  
  num = a-auxnum;//123.45678-123 -> 0.45678
  println(num);
  auxnum2=a-num;//123.45678-0.45678 -> 123.0
  while(d<limit)
  {
    auxnum2=(auxnum2)*10;
    auxnum2=(auxnum2)%1;
    d++;
    println("res:", d, "num", auxnum2);
  }
  return d;
}

The problem is that the print console shows the following:

3
123.0
res: 1 num 0.5677948
res: 2 num 0.677948
res: 3 num 0.77948
res: 4 num 0.7947998
res: 5 num 0.94799805
5

from that, I can take the first digit after the dot and I think this will get me back the digits of the float number, but I realize that those numbers are not correct, those should be something like:

res: 1 num 0.5678
res: 2 num 0.678
res: 3 num 0.78
res: 4 num 0.8
res: 5 num 0.0

Isn’t that correct?

But I dont know how to get that, I dont know if floating numbers get some errors when operating other numbers with them. So I wonder how can I get the number of digits without using number to string conversion techniques?

Many thanks in advance for any guidance

int numb_d(float n){
int nb=0;
while(((float)pow(10,nb))*n!=(int) (((float)pow(10,nb))*n)) nb++;
return nb;
}

This method should suffice.
It basicly always moves the comma one digit to the left and chops the digits after the comma of. And checks if choppign the digits of made a difference.

I hope I could help!

3 Likes

via String

float a1= 12.345678; 

println (a1);
String s1 = str(a1);
println (s1);
int pointPos = s1.indexOf("."); 
String s2 = s1.substring(pointPos+1, s1.length());
println(s2);
println(s2.length());

1 Like

There is an easier String variant

int numb_d2(float n){
  String strn=str(n);
  return strn.length()-strn.indexOf(".")-1;
}

Additionally juanjoc specifficly asked for a non-String solution.

1 Like

Float has some… annoying properties when it’s about rounding. Try the following:

  println(1234.45678);

it should return 1234.45678 in the console but it returns 1234.4568 instead. Some operations can cause it to randomly round and when multiplying with numbers >1 java might go crazy and add some junk-data. This is exactly what happened in your case together with a few other errors.

Another thing is: float only can have a maximum of 8 digits in total. For more digits try double. When defining a double don’t forget to add an d at the end of you number e.g.

10.1234567890234d
1 Like

This method should suffice.
It basicly always moves the comma one digit to the left and chops the digits after the comma of. And checks if choppign the digits of made a difference.

I hope I could help!

Wow, this is a very short and usefull code @NumericPrime . I was trying to get more digits with your code (using double cast), but the compiler shows me error of conversion. Is there a way to get more digits with your code?

Thanks

Thanks @Chrisir for your reply. I was looking for a method that doesnt use any string coversion, but Its ok.

int numb_d(double n){
int nb=0;
while(((double)pow(10,nb))*n!=(int) (((double)pow(10,nb))*n)&&nb<=11) nb++;
return nb;
}

this code will work up to 10 total digits. Then this code too will start having problems with calculating results.
Then up to a total of 16 digits the String conversion methods will still work and then the capacity of double is full.

1 Like

I think there’s a basic confusion in the question. One thing is the floating point number as it’s stored, and another is how many decimal places are printed. However you’ve viewed it, it’s been converted to a string and something has chosen how many decimal places to show. Suppose you set the value to √2 or PI, we know there are infinite decimal places, but we don’t usually print them all. (Depending on the storage type only a certain number can be relied on to be correct.)

You could avoid calling it a string, and calculate each decimal digit separately, but you still have to chose arbitrarily when to stop.

Well, that’s perfect, this will have more digits(up to 16) also because of the space available of the variable type(double). But that’s very good. Thank you @NumericPrime . I will choose your float input answer because of my query, but also the double one is optional for me

1 Like

Hi @RichardDL. Well in the Java variable type documentation, the float type only stores 7 decimal digits (4 Bytes) and the other decimal digits will give you some error if you work with so tiny numbers (1E-[7 to 38]). Isn’t it?. Also, processing in the terminal shows only 6 digits for every decimal number (float or double) and I couldn’t counting the numbers because I missed that floating numbers only work with 7 decimal digits and I wanted more. But now I realized that it is because of the variable type and it works up to 16 digits for accurate math operations, more digits I think that come from ALU aproximation of every PC. I am not sure.

I think you’re assuming precision (or number of significant digits) and number of decimal places are the same thing. Suppose it only stores 7 digits, that might be 1.234567 or 0.01234567 or anything similar between +/- 10E38. This page has a good explanation of float and double and it says that Java uses IEEE 754 Floating-Point. Now we know that, we can play with this floating point converter.

Yes, for more precision there is the double type.

You can control how Processing prints e.g. try println(String.format("%12.10f", PI));

Different CPUs may have different characteristics, but we trust that whoever wrote the compiler knew about that and programmed accordingly. Some years ago it was common to have a CPU and separate Floating-Point Processor. Or maybe for economy the FPP was missing, so the programs used floating point emulation code.

1 Like

Hello @Richard,

In the example you provided the Processing version of PI is a float:
float PI = (float) Math.PI;

This may not be obvious to everyone.

The example you provided will not correctly display PI to 10 decimal digits.

This:
println(String.format("%12.20f", PI)); //Your example to try... I changed decimal places to 20

Is the equivalent of this:
println(String.format("%12.20f", (double) ((float) Math.PI)));

And will not restore the significant digits that are lost casting from a float to a double.

This will display PI with the correct significant digits available:
println(String.format("%12.20f", Math.PI)); // double precision floating point

I stumbled across this years ago and and sorted it out at that time… it is important to provide clarity on this.

References:
https://github.com/processing/processing4/blob/master/core/src/processing/core/PConstants.java
https://en.wikipedia.org/wiki/Pi
https://en.wikipedia.org/wiki/Double-precision_floating-point_format

Example:

println(String.format("%12.20f", PI));
println();

println(String.format("%12.20f", (double) ((float) Math.PI)));
println();

println(String.format("%12.20f", Math.PI));
println();

:)

@glv, thanks for that, I should have used a smaller example value, or investigated more.

1 Like

Hello @RichardDL ,

Thanks for highlighting the formatting options.

I simply raised one of the issues with this.

This caught my attention because it was something that I explored ad nauseum in the past and again recently.

:)

Very interesting!. I did not know that not also Math.PI stores the real number of pi but PI keyword does not contain all the real digits.

1 Like