How can I get more accurate values by dividing two long?

Asked

Viewed 1,237 times

3

I’m programming a CNC on my own, and I’m in the middle of my code, and now I have two variables like long which, when divided results in an exact fractional value, but the Arduino returning a fractional value of only 2 houses.

long x = 99;
long y = 9;
long z = 9999;
long m = 9999;

(double)x/(double)m; //resulta em 0.01
(double)y/(double)m; //resulta em 0.00
(double)z/(double)m; //resulta em 1.00

How can I get more accurate values by dividing two values long?

Obs.: The maximum result of the division will be 1.00

  • Hello Gabriel, for a more precise answer and within the context of the Antarctic, please let me know which Arduino is using? Arduino Mega (or other family) or Arduino DUE (or similar)?

2 answers

2


(double)x/(double)m; //resulta em 0.01
(double)y/(double)m; //resulta em 0.00
(double)z/(double)m; //resulta em 1.00
99/9999 = 0.00990099(0099...)  
9/9999 = 0.00090009(0009...)

Maybe your problem is in printf(), not in the calculation:

printf(" com 2 dígitos de precisão: %.2f\n", 9.0/9999);
printf("                   default: %f\n", 9.0/9999); // 6 dígitos
printf("com 15 dígitos de precisão: %.15f\n", 9.0/9999);

that gives the result:

% ./a.out
 com 2 dígitos de precisão: 0.00
                   default: 0.000900
com 15 dígitos de precisão: 0.000900090009001
  • I think the doubles of the Arduino does not have capacity for 15 digits, only for 6 or 7.

  • Oh so that was it, I did not expect this behavior from Serial, so I was walking in circles, thanks for the help :D

  • No doubt the use of the printf() function and its variants is the best choice to format string outputs in a common C program, but in Arduino, this function will consume 1.5k more program memory, which may be important in your application. Not to mention the complexity (for a beginner) involved for its use with Arduino.

1

See in principle your problem is in using the function print/println of the object Serial these functions when dealing with type numbers float and double allows you to specify how many digits will be used for the fractional part of the given number. The default is two so your problem comes down to this, use a larger number of houses as in the example below where I used 30 houses, which is well beyond the capable resolution of the Arduino, whatever the architecture used.

But Attention, there are some knowledge that you may already have, but it is important to strengthen.

Arduino MEGA uses 8-bit microcontrollers from the AVR family, so the numeric type you chose, long occupies four bytes but does not allow fractions or floating point.

Therefore, you need to make one casting for a type of greater precision, being Arduino MEGA or another 8-bit family, it won’t make a difference in using Float or Double, you will have the same accuracy as 6 to 7 digits, with the limit values being 3.4028235E+38 at most and at least -3.4028235E+38.

But in the Arduino DUE family or ARM microcontrollers that are 32 bits, you will have a greater precision using the Double type since this will occupy 8 bytes (even the documentation saying that double and long have the same size), and these have 15 digit accuracy.

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

  long x = 234;
  long y = 343;
  long z = 731;

   Serial.println(x/y);
   Serial.println(x/(float)y,30);
   Serial.println(x/(double)y,30);

   Serial.println(x/z);
   Serial.println(x/(float)z,30);
   Serial.println(x/(double)z,30);

   Serial.println(y/z);
   Serial.println(y/(float)z,30);
   Serial.println(y/(double)z,30);

   Serial.println(z/y);
   Serial.println(z/(float)y,30);
   Serial.println(z/(double)y,30);

}

void loop() {
  // put your main code here, to run repeatedly:

}

In the above code, if executed on Arduino Mega (or another of family AVR - 8-bits) will have the following result:

58
58.500000000000000000000000000000  
58.500000000000000000000000000000

0
0.320109415054321289062500000000
0.320109415054321289062500000000

0
0.005471956253051757812500000000
0.005471956253051757812500000000

182
182.750000000000000000000000000000
182.750000000000000000000000000000

And in turn, in the Arduino DUE (and others of family ARM - 32-bits) will give the following result:

58
58.500000000000000000000000000000
58.500000000000000000000000000000

0
0.320109426975250244140625000000
0.320109439124487016314901666191

0
0.005471956450492143630981445312
0.005471956224350204678330555907

182
182.750000000000000000000000000000
182.750000000000000000000000000000

ATTENTION

Note the accuracy failure that occurs in the Arduino DUE when using float, and asks the Serial.println() print to 30 decimal places.

Sizes of Types

Long

32 bits (4 bytes), from -2,147,483,648 to 2,147,483,647

Double

3.4028235E+38 max and minimum -3.4028235E+38. In Arduino MEGA and family occupy (4 bytes) of information.

In Arduino DUE and family occupy (8 bytes) of information.

Float

Identical to Double in the Arduino Mega and family, but care 2.0 is different from (4/2.0), due to the method of numerical coding adopted (IEEE 754 for 32-bit floating point numbers).

In Arduino DUE it presents unexpected results when using greater precision.

int (Integer)

From -32,768 to 32,767 for the Arduino Mega and family, as it occupies 2 bytes

In Arduino Due, it uses 32-bit (4-byte). and therefore from -2,147,483,648 to 2,147,483,647 or identical to long

More information:

  1. https://www.arduino.cc/en/Reference/Long
  2. https://www.arduino.cc/en/Reference/Double
  3. https://www.arduino.cc/en/Reference/Float
  4. https://www.arduino.cc/en/Reference/Int
  5. http://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html
  6. https://pt.wikipedia.org/wiki/IEEE_754
  7. http://carlosdelfino.eti.br/logicadeprogramacao/nivel_4/Representando_Numeros_em_Ponto_Flutuante/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.