Calculator program output precision

Hey all!

I found a project video on Youtube and followed it along and got a working calculator.
That was fun and very informative, however the output precision of the calculator is only two places past the decimal point and it also rounds up the last digit.
It’s a pretty interesting program that uses string manipulation to figure out the first number, operation, and second number.
For context here is the code in complete:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSans9pt7b.h>
#include "String.h"
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);




static const unsigned char PROGMEM calc[] =
{0x01, 0xFF, 0xFF, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x60, 0x0C, 0x00, 0x00, 0x30,
0x08, 0x3F, 0xFC, 0x10, 0x08, 0xE0, 0x07, 0x10, 0x09, 0x80, 0x01, 0x90, 0x09, 0x00, 0x00, 0x90,
0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90,
0x09, 0x00, 0x00, 0x90, 0x09, 0x80, 0x01, 0x90, 0x08, 0xE0, 0x07, 0x10, 0x08, 0x3F, 0xFC, 0x10,
0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x21, 0x84, 0x10,
0x08, 0x73, 0xCE, 0x10, 0x08, 0x5A, 0x5A, 0x10, 0x08, 0x73, 0xCE, 0x10, 0x08, 0x00, 0x00, 0x10,
0x08, 0x00, 0x00, 0x10, 0x08, 0x73, 0xCE, 0x10, 0x08, 0x5A, 0x5A, 0x10, 0x08, 0x73, 0xCE, 0x10,
0x0C, 0x21, 0x84, 0x30, 0x06, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0xC0, 0x01, 0xFF, 0xFF, 0x80

};

 int operacija=0;

void setup()   {                


Serial.begin(9600);
for(int i=0;i<17;i++)
pinMode(i,INPUT_PULLUP);
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)

 

  // Clear the buffer.
  display.clearDisplay();
  display.setFont(&FreeSans9pt7b);
    
  display.setTextColor(WHITE);
  display.setCursor(36,12);
  display.print("Arduino");
  display.setCursor(36,31);
  display.print("calculator!");
  display.drawBitmap(0, 0,  calc, 32, 32, 1);
  display.display();
delay(2000);
  display.clearDisplay();



    display.setFont();
  display.setTextSize(2);
 

  
}
int changeNumber=0;
String num1="";
String num2="";
String broj="";
int stis[17]={0} ;
void loop() {
  display.clearDisplay();
for(int i=0;i<15;i++)
  {
  if(digitalRead(i)==0)
      {
      if(stis[i]==0)
        {
          if(i<10)
          broj=broj+i;

          if(i==10)
          broj=broj+"+";

           if(i==11)
          broj=broj+"-";

           if(i==12)
          broj=broj+"*";

           if(i==13)
          broj=broj+"/";

           if(i==14)
          broj=broj+".";

          
          
          
          stis[i]=1;
        }
      }else{stis[i]=0;}  
  }

 if (digitalRead(16)==0)
 {
  if(stis[16]==0)
     {
      broj="";
      stis[16]=1;
      
      }
  
  }else{stis[16]=0;}

 if(digitalRead(15)==0)
    {
      float n1=0.0000;
      float n2=0.0000;
      float res=0.0000;
     
      if(stis[15]==0)
            {
            
            stis[15]=1;
            int duz=broj.length();
            for(int i=0;i<duz;i++)
                   
                   {
                    if(broj.charAt(i)=='+'){
                    changeNumber=1;
                    operacija=1;}

                    if(broj.charAt(i)=='-'){
                    changeNumber=1;
                    operacija=2;}

                     if(broj.charAt(i)=='*'){
                    changeNumber=1;
                    operacija=3;}

                      if(broj.charAt(i)=='/'){
                    changeNumber=1;
                    operacija=4;}


                    
                   if(changeNumber==0)
                   {
                    char slovo=broj.charAt(i);
                   num1=num1+slovo;
                   }
                  
                     if(changeNumber==2){
                     char slovo=broj.charAt(i);
                   num2=num2+slovo;}

                     if(changeNumber==1)
                    changeNumber=2;
                   
                   
                    }
                     n1=num1.toFloat();
                     n2=num2.toFloat();
                    
                     if(operacija==1){
                     res=n1+n2;}
                         if(operacija==2){
                     res=n1-n2;}
                         if(operacija==3){
                     res=n1*n2;}
                         if(operacija==4){
                     res=n1/n2;} 
                    
                     Serial.println(n1); Serial.println(n2);
                      Serial.println(n1/n2);
                    broj="";
                    int tenths=res/10;
                    float remain=res-(tenths*10);
                    broj=(String)res;
                    changeNumber=0;
                    num1="";
                    num2="";
                    operacija=0;
                    
            }
      
    }else{stis[15]=0;}
  
  display.setCursor(0,11  );
   if(broj=="")
   {
    display.println(0);
    }else{
   display.println(broj);}
 display.display();
}

I suspect that it is within this snippet of code that my precision goes out the door.

                    broj="";
                    int tenths=res/10;
                    float remain=res-(tenths*10);
                    broj=(String)res;

But since I’m here asking you can be sure I’m not certain.
Really what I need is precision to the fifth place after the decimal place and if someone could give me some guidance or just tell me what I’m missing that would be greatly appreciated.

very informative

Really? The program doesn't have even a single inline comment. Do they explain anything at all in the video (I don't surf to videos as they are generally amateurish and tedious, I only read here)?

What exactly are you trying to achieve? To get a working calculator, or just understand some code? If you want a working calculator and you have no clue what this does, just look for another one.

Since the results in variables “remain” and “tenths” are not used anywhere in the program, that isn’t the cause of your issue.

Arduino floats are limited to 6-7 digits of precision. So depending how many digits you have before the decimal point, 5 is about as good as you are going to get after it.

Unfortunately Arduino platform does not support double precision on most boards, so you are out of luck.

Edit:
There is no tutorial on the code in the video. Source is just provided “as is” for download.

To be brutally honest it’s far from being a great example…

  1. No consistent coding style (brace styles and indents are all over the place).
  2. For some reason it uses separate input pins for all the switches instead of a matrix - easy to understand I suppose
  3. Some variable names in English, the rest apparently in Croatian (according to Google) - at least be consistent
  4. Very few comments

Personally I wouldn’t use it as a learning example - Sorry.

Well a quick summation is that this program uses the string broj to accept all input. Once you trigger the calculate button it uses a for loop combined with a string.length() to seperate the two values into seperate strings num1 and num2. At the same time it compares characters at every position in the broj string with .charAt() to determine the operation and toggles operacija

My goal is to have a calculator program that can output precise values to the fifth place past the decimal so if I were to add 1+.81256 my output would be 1.81256 and not 1.81 which is what this program currently gives me.

Obviously I already have the hardware soldered together so the most logical way to get to my goal is to find out where and why the program is rounding off digits.

pcbbc:
Since the results in variables “remain” and “tenths” are not used anywhere in the program, that isn’t the cause of your issue.

Arduino floats are limited to 6-7 digits of precision. So depending how many digits you have before the decimal point, 5 is about as good as you are going to get after it.

Unfortunately Arduino platform does not support double precision on most boards, so you are out of luck.

Edit:
There is no tutorial on the code in the video. Source is just provided “as is” for download.

To be brutally honest it’s far from being a great example…

  1. No consistent coding style (brace styles and indents are all over the place).
  2. For some reason it uses separate input pins for all the switches instead of a matrix - easy to understand I suppose
  3. Some variable names in English, the rest apparently in Croatian (according to Google) - at least be consistent
  4. Very few comments

Personally I wouldn’t use it as a learning example - Sorry.

Can you tell me what this line of code is doing?

broj=(String)res;

Instead of

   display.println(broj);}

try

   display.println(broj, 4);}

my output would be 1.81256 and not 1.81 which is what this program currently gives me.

Serial.print(float_value) defaults to 2 places past the decimal. Only the first 6 or 7 digits printed are meaningful.

You could try this one..

Arduino calculator

But you'd need a touchscreen to do it. Does make building it a lot easier though.

-jim lee

jremington:
Serial.print(float_value) defaults to 2 places past the decimal. Only the first 6 or 7 digits printed are meaningful.

Yes-I suspected that could also be a problem I faced.
How could I change that? Change the program to do a different type of output?

Check the reference page for Serial.print()

aarg:
Instead of

   display.println(broj);}

try

   display.println(broj, 4);}

Ah, unfortunately this gave me the error

no matching function for call to 'Adafruit_SSD1306::print(String&, int)'

"broj" is a String, which are frowned upon in this forum. Use of Strings causes memory problems and program crashes.

try

display.println(broj.toDouble(), 4);

...and keep in mind what he says above

aarg:
try

display.println(broj.toDouble(), 4);

...and keep in mind what he says above

Hmm--no compile time error, but it definitely breaks the program, since it's displaying a string that contains numbers and characters if I convert broj.toDouble I can no longer input +-*/ so I can not calculate anything.

Well aarg, I appreciate your attempt but I think I might just need to go beyond the scope of asking for programming assistance and probably create a new way to deal with this problem on my own.
The links to the reference page on strings was helpful, and I guess I'll just need to do more research.

This line converts the result of the previous calculation, res, to a String, which you later add to, then try to print.

broj=(String)res;

Instead, skip the totally unnecessary and ill advised String conversion, and use the following to directly print the result to four decimal places:

display.print(res,4);

All the extra stuff, like printing =+-/* symbols, can be accomplished with similar, very simple display.print() statements. For example:

 float res=3.0 + 1.1235;
display.print(res,4);
display.print(" = ");
display.print(3.0,0);
display.print(" + ");
display.println(1.1235, 4);