Arduino makes parts of text disappear in Serial.println() (SOLVED by myself)

Thank you to all who tried solving this problem and giving out suggestions!
Scroll down to see the solution.

EDIT: I used my Arduino on Autodesk Tinkercad, not on the actual Arduino, which might be the reason for my errors.

Whenever I try to test my calculator to see if it is working, for some reason, when it gets to the part where it performs a calculation in my code, the part where it prints out the equation with the numbers and the answer just disappears to no avail.

float b;
String mode;
String choice;
float e = 2.718281828459045;

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("Welcome to Alculus Calculator!");
  Serial.println("Pick a math operation to calculate: '+', '-', '*', '/', '%', '^', '!', 'sqrt()', 'root()', 'sin()', 'cos()', 'tan()', 'csc()', 'sec()', 'cot()', 'arcsin()', 'arccos()', 'arctan()', 'arccsc()', 'arcsec()', 'arccot()', 'log()', 'ln()', Combinatiorics 'nCr', Permutation 'nPr', Solve for x in a polynomial 'Px', Polynomial Multiplication 'Pm', Polynomial Divison 'Pd', Solve for Arithmetic Series 'A', Solve for Geometric Series 'G'");
  while (Serial.available() == 0){}
  String c = Serial.readString();
  if (c == "+" || c == "-" || c == "*" || c == "/" || c == "%" || c == "^" || c == "!" || c == "sqrt()" || c == "sin()" || c == "cos()" || c == "tan()" || c == "csc()" || c == "sec()" || c == "cot()" || c == "arcsin()" || c == "arccos()" || c == "arctan()" || c == "arccsc()" || c == "arcsec()" || c == "arccot()"){
    if (c == "sin()" || c == "cos()" || c == "tan()" || c == "csc()" || c == "sec()" || c == "cot()" || c == "arcsin()" || c == "arccos()" || c == "arctan()" || c == "arccsc()" || c == "arcsec()" || c == "arccot()"){
      Serial.println("Would you like your |number (for non-inverse trig functions)/answer (for inverse trig functions)| in 'radians' or 'degrees'? If you do not type a valid answer, your number will be in radians. Type here: ");
      while (Serial.available() == 0){}
      mode = Serial.readString();
    }Serial.println("Type a number here: ");
    while (Serial.available() == 0){}
    float a = Serial.parseFloat();
    if (!(c == "!" || c == "sqrt()" || c == "sin()" || c == "cos()" || c == "tan()" || c == "csc()" || c == "sec()" || c == "cot()" || c == "arcsin()" || c == "arccos()" || c == "arctan()" || c == "arccsc()" || c == "arcsec()" || c == "arccot()")){
      Serial.println("Type another number here: ");
      while (Serial.available() == 0){}
      b = Serial.parseFloat();
    }if (c == "+"){
      Serial.println(String(a) + "+" + String(b) + "=" + String(a+b));
    }if (c == "-"){
      Serial.println(String(a) + "-" + String(b) + "=" + String(a-b));
    }if (c == "*"){
      Serial.println(String(a) + "*" + String(b) + "=" + String(a*b));
    }if (c == "/"){
      if (b != 0){
      	Serial.println(String(a) + "/" + String(b) + "=" + String(a/b));
      }else{
        Serial.println("You cannot divide a number by 0. Wait for 3 seconds.");
        delay(3000);
        Serial.println("\n\n");
      }
    }if (c == "%"){
      Serial.println(String(a) + "%" + String(b) + "=" + String( float(long(a*pow(10, 2))%long(b*pow(10, 2)))/pow(10, 2) ));
    }if (c == "^"){
      Serial.println(String(a) + "^" + String(b) + "=" + String(pow(a, b)));
    }if (c == "!"){
      Serial.println(String(a) + "!" + "=" + String(gamma(a)));
    }if (c == "sqrt()"){
      Serial.println("sqrt(" + String(a) + ")=" + String(squareRoot(a)));
    }if (c == "sin()"){
	  Serial.println("sin(" + String(a) + ")=" + String(sine(a)));
    }if (c == "cos()"){
	  Serial.println("cos(" + String(a) + ")=" + String(cosine(a)));
      // sine(a+pi/2)
    }if (c == "tan()"){
	  Serial.println("tan(" + String(a) + ")=" + String(sine(a)/cosine(a)));
    }if (c == "csc()"){
	  Serial.println("csc(" + String(a) + ")=" + String(1/sine(a)));
    }if (c == "sec()"){
	  Serial.println("sec(" + String(a) + ")=" + String(1/cosine(a)));
    }if (c == "cot()"){
	  Serial.println("cot(" + String(a) + ")=" + String(cosine(a)/sine(a)));
    }if (c == "arcsin()"){
      Serial.println("arcsin(" + String(a) + ")=" + String(arcS(a)));
    }if (c == "arccos()"){
	  Serial.println("arccos(" + String(a) + ")=" + String(PI/2-arcS(a)));
    }if (c == "arctan()"){
	  Serial.println("arctan(" + String(a) + ")=" + String(arcT(a)));
      //arcS(a/squareRoot(1 + x*x))
    }if (c == "arccsc()"){
	  Serial.println("arccsc(" + String(a) + ")=" + String());
    }if (c == "arcsec()"){
	  Serial.println("arcsec(" + String(a) + ")=" + String());
    }if (c == "arccot()"){
	  Serial.println("arccot(" + String(a) + ")=" + String());
    }
  }else{
    Serial.println("\n\n\nPlease type a valid math operation that is given to you by the calculator. Wait for 3 seconds.");
    delay(3000);
    Serial.println("\n\n");
  }Serial.println("\n");
}

float squareRoot(float n){
  float i;
  while ((i*i)<n){
    if ((i*i)<n){
      i += 0.01;
    }
  }if ( abs((n-i*i)) < abs((n-(i-0.01)*(i-0.01))) ){
    return i;
  }else{
    return i-0.01;
  }
}

float sine(float n){
  float ans;
  float place;
  while (n > PI){
    n -= PI;
  }while (n < -1*PI){
    n += PI;
  }for (int i=1; i<=21; i+=2) {
    place = pow(n, i);
    for (int j=1; j<=i; j++) {
      place = place/j;
    }if (((i+1)/2)%2 == 0){
      ans += place;
    }else{;
      ans -= place;
    }
  }return ans;
}

float cosine(float n){
  float ans;
  float place;
  for (int i=0; i<=20; i+=2) {
    place = pow(n, i);
    for (int j=1; j<=i; j++) {
      place = place/j;
    }if ((i/2)%2 == 1){
      ans += place;
    }else{;
      ans -= place;
    }
  }return ans;
}

float arcS(float n){
  float ans;
  float place;
  for (int i=1; i<=21; i+=2) {
    place = pow(n, i)/i;
    for (int j=1; j<=i-1; j++) {
      if (j%2 == 1){
        place *= j;
      }else{
        place /= j;
      }
    }ans += place;
  }return ans;
}

float arcT(float n){
  float ans;
  float place;
  if (abs(n) < 1){
    return sine(n);
  }else{
    if (n > 0){
      ans = PI/2;
    }else{
      ans = -1*PI/2;
    }for (int i=1; i<=21; i+=2) {
      place = 1/(i*pow(n, i));
      if (((i+1)/2)%2 == 1){
        ans += place;
      }else{;
        ans -= place;
      }
    }return ans;
  }
}

float gamma(float n){
  n += 1;
  int g = 7;
  float lanczos[] = {
    0.99999999999980993,
    676.5203681218851,
    -1259.1392167224028,
    771.32342877765313,
    -176.61502916214059,
    12.507343278686905,
    -0.13857109526572012,
    9.9843695780195716e-6,
    1.5056327351493116e-7};
  if (n < 0.5){
    return PI/(sine(PI*n)*gamma(1-n));
  }else{
    n -= 1;
    float place = lanczos[0];
    for (int i=1; i<=9; i++){
      place += lanczos[i]/(n+i);
    }float v = n + g + 0.5;
    return squareRoot(2*PI)*pow(v, n+0.5)*pow(e, -1*v)*place;
  }
}

For example, if I wanted to do a simple math operation such as "3.00+3.00", I would just get "=6.00" instead of "3.00+3.00=6.00".
If I wanted to do a complicated math operation such as "sin(55.3)", I would get absolutely nothing instead of "sin(55.3)=-0.95"

Here is the code where it cuts off the text:

if (c == "+"){
      Serial.println(String(a) + "+" + String(b) + "=" + String(a+b));
    }if (c == "-"){
      Serial.println(String(a) + "-" + String(b) + "=" + String(a-b));
    }if (c == "*"){
      Serial.println(String(a) + "*" + String(b) + "=" + String(a*b));
    }if (c == "/"){
      if (b != 0){
      	Serial.println(String(a) + "/" + String(b) + "=" + String(a/b));
      }else{
        Serial.println("You cannot divide a number by 0. Wait for 3 seconds.");
        delay(3000);
        Serial.println("\n\n");
      }
    }if (c == "%"){
      Serial.println(String(a) + "%" + String(b) + "=" + String( float(long(a*pow(10, 2))%long(b*pow(10, 2)))/pow(10, 2) ));
    }if (c == "^"){
      Serial.println(String(a) + "^" + String(b) + "=" + String(pow(a, b)));
    }if (c == "!"){
      Serial.println(String(a) + "!" + "=" + String(gamma(a)));
    }if (c == "sqrt()"){
      Serial.println("sqrt(" + String(a) + ")=" + String(squareRoot(a)));
    }if (c == "sin()"){
	  Serial.println("sin(" + String(a) + ")=" + String(sine(a)));
    }if (c == "cos()"){
	  Serial.println("cos(" + String(a) + ")=" + String(cosine(a)));
      // sine(a+pi/2)
    }if (c == "tan()"){
	  Serial.println("tan(" + String(a) + ")=" + String(sine(a)/cosine(a)));
    }if (c == "csc()"){
	  Serial.println("csc(" + String(a) + ")=" + String(1/sine(a)));
    }if (c == "sec()"){
	  Serial.println("sec(" + String(a) + ")=" + String(1/cosine(a)));
    }if (c == "cot()"){
	  Serial.println("cot(" + String(a) + ")=" + String(cosine(a)/sine(a)));
    }if (c == "arcsin()"){
      Serial.println("arcsin(" + String(a) + ")=" + String(arcS(a)));
    }if (c == "arccos()"){
	  Serial.println("arccos(" + String(a) + ")=" + String(PI/2-arcS(a)));
    }if (c == "arctan()"){
	  Serial.println("arctan(" + String(a) + ")=" + String(arcT(a)));
      //arcS(a/squareRoot(1 + x*x))
    }if (c == "arccsc()"){
	  Serial.println("arccsc(" + String(a) + ")=" + String());
    }if (c == "arcsec()"){
	  Serial.println("arcsec(" + String(a) + ")=" + String());
    }if (c == "arccot()"){
	  Serial.println("arccot(" + String(a) + ")=" + String());
    }

I tried the solutions from other similar Arduino posts, but they did not help. What do you think I should do?

Have a look at the print statements , they are not consistent with the brackets .

You also have print statements followed by + some variable mixed in there which might not react how you think it should ?

1 Like


I need a wider screen.

You are printing a message consisting of 429 characters on one line - not very user friendly.

I see '3.00+3.00=6.00' and 'sin(55.30)=-0.95'.

The way you deal with your input is not great either for your goal

There is no way your test for c == "sin()" to work out for example

You need a much better parser and not depend on the readString() function which will read all the input until the timeout.

PS: your float can’t deal with that precision level. If your are using a 32 bit MCU you could use the double type instead of float to get more decimal digits.

1 Like

Hopefully you are not compiling for an UNO or any other board with a small amount of ram, the extensive use of String will very likely cause problems.

Down on line 188 you have the following:

    for (int i = 1; i <= 9; i++) {
      place += lanczos[i] / (n + i);
    } float v = n + g + 0.5;

The lanczos array index starts and 0, the last element is 8, 9 is out of range.

1 Like

LOL.

Is that some kind of slap on the wrist, or is division by zero possible if only we wait three seconds?

a7

1 Like

The solution: Separate different terms from

Serial.println(String(a) + "+" + String(b) + "=" + String(a+b));

into

Serial.print(String(a)); Serial.print("+"); Serial.print(String(b)); Serial.print("="); Serial.print(String(a+b));

Thank you to all who contributed to this problem and giving out suggestions!
Edit: I also thank those who contributed to this problem after I wrote this original reply/post.

Hi @Alculus,

feel free to check this version of your code on Wokwi:

https://wokwi.com/projects/436924052037003265

/*
    Forum: https://forum.arduino.cc/t/arduino-makes-parts-of-text-disappear-in-serial-println/1396591
    Wokwi: https://wokwi.com/projects/436924052037003265

    The mathematic functions provided by the TO have not been checked for correctness!
    There is still room for improvement ...

    2025/07/20

    ec2021

*/

enum operations { HELP, PLUS, MINUS, TIMES, DIVIDE, MODULO, POWER, GAMMA,
                  SQRT, SIN, COS, TAN, CSC, SEC, COT, ARCSIN,
                  ARCCOS, ARCTAN, ARCCSC, ARCSEC, ARCCOT
                };

char operation[][9] = {
  "help", "+",  "-",  "*",  "/",  "%",  "^",  "!",  "sqrt",  "sin",  "cos", "tan",
  "csc",  "sec",  "cot",  "arcsin",  "arccos",  "arctan",  "arccsc",
  "arcsec", "arccot"
};
constexpr int noOfOps = sizeof(operation) / sizeof(operation[0]);
boolean hasOneParameter;
constexpr float e = 2.718281828459045;
constexpr int  maxChars = 11;
char cOperation[maxChars] = "";

float a;
float b;
float c;

void setup() {
  Serial.begin(115200);
  printOps();
  Serial.println(F("Input 'help' to print the Operators"));
}

void loop() {
  receiveOperation();
  evaluateOperation();
  delay(3000);
}

void receiveOperation() {
  Serial.println(F("Choose Operation"));
  getString(cOperation);
}

void getString(char *buff) {
  boolean done = false;
  int index = 0;
  while (!done) {
    if (Serial.available()) {
      char c = Serial.read();
      if (c < ' ') {
        done = (index > 0);
      } else {
        if (!(c == '(' || c == ')')) {
          buff[index++] = c;
        }
        done = (index == maxChars - 2);
      }
    }
  }
  buff[index] = 0x00;
  clearSerial();
}

void clearSerial() {
  while (Serial.available()) {
    char c = Serial.read();
  }
}

void evaluateOperation() {
  int mode = -1;
  for (int i = 0; i < noOfOps; i++) {
    if (strcmp(cOperation, operation[i]) == 0) {
      mode = i;
      break;
    }
  }
  if (mode == -1) {
    Serial.print(cOperation);
    Serial.println(F("\tUnknown or wrong operation"));
    return;
  }
  if (mode == HELP) {
    printOps();
    return;
  }
  printOperation(mode);
  Serial.println();
  a = getParameter(hasBrackets(mode) ? "Single " : "First ");
  if (!hasBrackets(mode)) {
    b = getParameter("Second");
  }
  doOperation(mode);
}


float getParameter(char *buf) {
  char cFloat[maxChars] = "";
  Serial.print(buf);
  Serial.print(F(" Parameter  = "));
  getString(cFloat);
  Serial.println(cFloat);
  return atof(cFloat);

}

void printOps() {
  Serial.println(F("*************************************"));
  for (int i = 0; i < noOfOps; i++) {
    printOperation(i);
    if (i % 5 == 4) {
      Serial.println();
    }
  }
  Serial.println(F("\n*************************************"));
}

boolean hasBrackets(int op) {
  if (op < 0 || op >= noOfOps) {
    return false;
  }
  return op >= GAMMA;

}

void printOperation(int i) {
  Serial.print(operation[i]);
  Serial.print( hasBrackets(i) ? "() " : "\t");
}

void doOperation(int opNo) {
  switch (opNo) {
    case PLUS:
      c = a +  b;
      break;
    case MINUS:
      c = a +  b;
      break;
    case TIMES:
      c = a *  b;
      break;
    case DIVIDE:
      if (b == 0) {
        Serial.println(F("Division by 0 not allowed!"));
        return;
      }
      c = a /  b;
      break;
    case MODULO:
      c = long(a) %  long(b);
      break;
    case POWER:
      c = pow(a, b);
      break;
    case GAMMA:
      c = gamma(a);
      break;
    case SQRT:
      c = squareRoot(a);
      break;
    case SIN:
      c = sine(a);
      break;
    case COS:
      c = cosine(a);
      break;
    case TAN:
      c = sine(a) / cosine(a);
      break;
    case CSC:
      c = 1 / sine(a);
      break;
    case SEC:
      c = 1 / cosine(a);
      break;
    case COT:
      c = cosine(a) / sine(a);
      break;
    case ARCSIN:
      c = arcS(a);
      break;
    case ARCCOS:
      c = PI / 2 - arcS(a);
      break;
    case ARCTAN:
      c = arcT(a);
      break;
    case ARCCSC:
    case ARCSEC:
    case ARCCOT:
      // TBD
      notImplemented();
      return;
      break;
    default:
      return;
  }
  printformatted(opNo);
}


void notImplemented() {
  Serial.println(F("Not yet implemented ..."));
}

void printformatted(int no) {
  if (hasBrackets(no)) {
    Serial.print(operation[no]);
    Serial.print('(');
    Serial.print(a);
    Serial.print(')' );

  } else {
    Serial.print(a);
    Serial.print(' ');
    Serial.print(operation[no]);
    Serial.print(' ');
    Serial.print(b);
  }
  Serial.print(" = ");
  Serial.println(c);
}

/******************************************************************/
/*                Functions as provided by TO                     */
/*                NOT CHECKED FOR CORRECTNESS                     */
/******************************************************************/

float squareRoot(float n) {
  float i;
  while ((i * i) < n) {
    if ((i * i) < n) {
      i += 0.01;
    }
  } if ( abs((n - i * i)) < abs((n - (i - 0.01) * (i - 0.01))) ) {
    return i;
  } else {
    return i - 0.01;
  }
}

float sine(float n) {
  float ans;
  float place;
  while (n > PI) {
    n -= PI;
  } while (n < -1 * PI) {
    n += PI;
  } for (int i = 1; i <= 21; i += 2) {
    place = pow(n, i);
    for (int j = 1; j <= i; j++) {
      place = place / j;
    } if (((i + 1) / 2) % 2 == 0) {
      ans += place;
    } else {
      ans -= place;
    }
  } return ans;
}

float cosine(float n) {
  float ans;
  float place;
  for (int i = 0; i <= 20; i += 2) {
    place = pow(n, i);
    for (int j = 1; j <= i; j++) {
      place = place / j;
    } if ((i / 2) % 2 == 1) {
      ans += place;
    } else {
      ans -= place;
    }
  } return ans;
}

float arcS(float n) {
  float ans;
  float place;
  for (int i = 1; i <= 21; i += 2) {
    place = pow(n, i) / i;
    for (int j = 1; j <= i - 1; j++) {
      if (j % 2 == 1) {
        place *= j;
      } else {
        place /= j;
      }
    } ans += place;
  } return ans;
}

float arcT(float n) {
  float ans;
  float place;
  if (abs(n) < 1) {
    return sine(n);
  } else {
    if (n > 0) {
      ans = PI / 2;
    } else {
      ans = -1 * PI / 2;
    } for (int i = 1; i <= 21; i += 2) {
      place = 1 / (i * pow(n, i));
      if (((i + 1) / 2) % 2 == 1) {
        ans += place;
      } else {
        ;
        ans -= place;
      }
    } return ans;
  }
}

float gamma(float n) {
  n += 1;
  int g = 7;
  float lanczos[] = {
    0.99999999999980993,
    676.5203681218851,
    -1259.1392167224028,
    771.32342877765313,
    -176.61502916214059,
    12.507343278686905,
    -0.13857109526572012,
    9.9843695780195716e-6,
    1.5056327351493116e-7
  };
  int maxIndex = sizeof(lanczos) / sizeof(lanczos[0]);
  if (n < 0.5) {
    return PI / (sine(PI * n) * gamma(1 - n));
  } else {
    n -= 1;
    float place = lanczos[0];
    for (int i = 1; i < maxIndex; i++) {
      place += lanczos[i] / (n + i);
    } float v = n + g + 0.5;
    return squareRoot(2 * PI) * pow(v, n + 0.5) * pow(e, -1 * v) * place;
  }
}

Compiled for an UNO with IDE 2.3.6:

Sketch uses 9006 bytes (27%) of program storage space. Maximum is 32256 bytes.
Global variables use 481 bytes (23%) of dynamic memory, leaving 1567 bytes for local variables. Maximum is 2048 bytes.

This code uses enumerations, a string list of operations and switch/case to handle the mathematics. The results are printed in a single function that just discriminates between operations with one or two parameters.

Have fun :wink:
ec2021

Your title says now « solved by myself »

What does it mean ? There is no way the code base you submitted could ever handle input like sin(55.3)

Did you lower expectations? How did you solve the issue? Just curious

Reply to J-M-L Jackson
Refer to the links:
combine "wiki" with the rest of the link on the next line (wikimedia.org...):
wiki media.org/api/rest_v1/media/math/render/svg/158a0ae14d1c9e0d1dc21c268f7e2169b9066dc7
www.efunda.com/math/taylor_series/images/inverse_trig.gif
They helped me make my sin, cos, and arctan functions. Since these series switch from positive to negative for each progressive term, this helps with faster precision with my own answers. However, for arcsin, I made a brute force method by trying to get the answer, 'i', by doing this: sin(i)==n (n is the user input)
Additionally, the format that was presented in was in float. For some reason, Arduino ONLY shows up to 2 decimal places in float values. However, float values actually extend way more to a range of values for decimal places from 13 to 15. Hopefully that answers your question.
Filler-in Details:
I just recently finished all of my trigonometric functions, especially the inverse ones. It is not in the post, though. I discovered that they were bugged, and I just fixed them. The problem I faced in this post was when the text part cut off. However, since I already fixed it, my only main issue was getting the trigonometric functions to be at least two decimal places accurate, which was what I needed. I just finished that during 4:00 AM in the morning, so no big deal or whatsoever- just ONLY wanted to make something humorous.

Reply to ec2021
Thank you for making a solution for me! Even though I have already solved my own issue before you posted your own version of the code, it looks very well organized and professional unlike mine, where I just try to compress everything. Anyways, I just fixed all of my trigonometric functions, especially the inverse ones. The issues of the pre-existing trigonometric functions that I made are also fixed. They now work as intended. The purpose of the answer precision was meant to be 2 decimal places. However, I made them accurate up to at least 7 decimal places. If you want more details on how I have made them, you can go read at the reply/post above this one. It specifically addresses doubts from J-M-L Jackson. If you want more explaining, I am happy to explain the trigonometric functions I made in depth. Even though it will take me a while to write, I enjoy working and explaining on math and coding/programming. They are some of my hobbies.

Reply to J-M-L Jackson
The float values are displayed to two decimal places. However, Arduino keeps track of the other decimal places that extend to 13 to 15 decimal places. You can refer to the other reply I sent you. Thank you for expressing your thoughts!

That is because the conversion to String, and the print() function if you are printing directly, default to 2 decimal places when doing the conversion from float to ASCII. If you want more decimal places, you need to specify that by adding a 2nd argument to the String or print function:

    Serial.println("sin(" + String(a, 7) + ")=" + String(sine(a), 7));
    //prints float to 7 decimal places

Note that the float data type is limited to 7 significant digits (not decimal places) of precision. If you want 15 significant digits of precision, you need to use double, but that is not implemented on many of the Arduino boards because of the size of the code.

Thanks for your explanations.

Regarding high precision arithmetics you might be interested in the following links

https://austinhenley.com/blog/bignum1.html

https://github.com/giocip/ARDUINO_num7

or

https://docs.arduino.cc/libraries/fp64lib/

which have been created to overcome the precision limitations of standard data types (for the cost of memory and processing time).

Have fun!

If that code change fixed anything it was because your previous expressions were causing the trouble Strings make happen soon rather than later (probably) or never (you clan always hope).

a7

well, the printing is 2 decimal digits by default but it's just a parameter of the print() function when passing a floating point number.

Serial.println(1.234); 
Serial.println(1.234, 4); // will print with 4 digits after the decimal point

regarding your absurd claim that

you need to revisit the basics about the precision of float and double in IEEE representations.

This is governed by the number of bits allocated to the significand (aka mantissa), which determines how many significant digits can be represented.

In IEEE 754:

A float (single precision) uses 32 bits:
1 bit for the sign, 8 bits for the exponent, and 23 bits for the significand, with an implicit leading 1, giving effectively 24 bits of precision.

A double (double precision) uses 64 bits on 32 bits arduino but will be only 32 bits (ie same precision as a float) on UNO:
1 bit for the sign, 11 bits for the exponent, and 52 bits for the significand, with an implicit leading 1, giving effectively 53 bits of precision.

This bit width of the significand directly controls how finely numbers can be distinguished. The more bits in the significand, the smaller the difference between two adjacent representable values, and thus the higher the precision.

On average, a 32-bit IEEE 754 float gives about 7.2 decimal digits of precision, often rounded to 7 significant digits.

A 64-bit IEEE 754 double gives about 15.95 decimal digits of precision, typically rounded to 15 or 16 significant digits.