Go Down

Topic: Arduino Due Benchmark - Newton Approximation for Pi (Read 6 times) previous topic - next topic

securd

Dec 23, 2012, 08:15 pm Last Edit: Dec 24, 2012, 03:45 am by Coding Badly Reason: 1
After receiving my Due, I wanted to benchmark its numeric processing power as compared to the Mega.  I was also interested in understanding which of my standard Arduino shields and gadgets were compatible with the 3.3v I/O of the Due.

Being a recovering physicist, what better test than to approximate pi, and periodically display the approximation results on 1638 display!

I utilized the slowly-converging Newton Approximation for pi, which does a reasonably good job of calculating pi / 4, using the infinite series   1 - 1/3 + 1/5- 1/7 + 1/9 - 1/11 +...

This is simple to express in Arduino C, and uses the floating point libraries to further assess performance.  I tested a Due and a Mega, connected to a JY-LKM1638 V1.2 display module (which is based on the TM1638 controller chip).  The times required to traverse 100,000 iterations were as follows:

Due: 1785 ms
Mega: 6249 ms
(roughly 3.5x performance difference)

Upping ITERATIONS to 10000000 (ten million) gets pi accurate to about 8 significant digits!

Photo attached, and sketch follows:

-----

Code: [Select]
//
// Pi_2
//
// Steve Curd
// December 2012
//
// This program approximates pi utilizing the Newton's approximation.  It quickly
// converges on the first 5-6 digits of precision, but converges verrrry slowly
// after that.  For example, it takes over a million iterations to get to 7-8
// significant digits.
//
// For demonstration purposes, drives a JY-LKM1638 display module to show the
// approximated value after each 1,000 iterations, and toggles the pin13 LED for a
// visual "sign of life".
//
// I wrote this to evaluate the performance difference between the 8-bit Arduino Mega,
// and the 32-bit Arduino Due.
//
// Benchmark results for 100,000 iterations (pi accurate to 5 significant digits):
//
// Due: 1785 ms
// Mega: 6249 ms
//
// 1638 display module connections:
// VCC -> 3.3v
// GND -> GND
// DIO -> Pin 8
// CLK -> Pin 9
// STB0 -> Pin 7
//
//
#define ITERATIONS 20000000L    // number of iterations
#define FLASH 1000            // blink LED every 1000 iterations

#include <TM1638.h>

// TM1638 module(DIO, CLK, STB0)
TM1638 module(8, 9, 7);

void setup() {
 pinMode(13, OUTPUT);
 Serial.begin(57600);
}

void loop() {
 
 unsigned long start, time;
 unsigned long niter=ITERATIONS;
 int LEDcounter = 0;
 boolean alternate = false;
 unsigned long i, count=0;        /* # of points in the 1st quadrant of unit circle */
 double x = 1.0;
 double temp, pi=1.0;

 start = millis();  

 Serial.print("Beginning ");
 Serial.print(niter);
 Serial.println(" iterations...");
 Serial.println();
 
 count=0;
 for ( i = 2; i < niter; i++) {
   x *= -1.0;
   pi += x / (2.0*(double)i-1);
   if (LEDcounter++ > FLASH) {
     LEDcounter = 0;
     if (alternate) {
       digitalWrite(13, HIGH);
       alternate = false;
     } else {
       digitalWrite(13, LOW);
       alternate = true;
     }
     temp = 40000000.0 * pi;
     module.setDisplayToDecNumber( temp, 0x80);
   }
 }

 time = millis() - start;
 
 pi = pi * 4.0;

 Serial.print("# of trials = ");
 Serial.println(niter);
 Serial.print("Estimate of pi = ");
 Serial.println(pi, 10);
 
 Serial.print("Time: "); Serial.print(time); Serial.println(" ms");
 
 delay(10000);
}


Moderator edit: [code] [/code] tags added.

stimmer

There might be an imbalance between your tests as on a Uno/Mega double is only really a float (32 bits) but on the Due I think it is full double precision (64 bits). Try it again using float on the Due, you should still get 7 digits of precision out of it.

securd

Ok, well, this is strange.  I changed all of the doubles to floats.  The Mega had exactly the same time (which reinforces your point).  However the time for the Due actually went UP.

For due...
double: 1785 ms
float: 2056 ms

I haven't had time to go through the floating point library, but do you suppose the Due handles all floating points as doubles by default?

Steve.

stimmer

#3
Dec 23, 2012, 09:11 pm Last Edit: Dec 23, 2012, 09:14 pm by stimmer Reason: 1
No, it's just a 'feature' of C++ which makes it quite hard to get it to do calculations as floats - basically any floating point constant is considered to be a double, then because the calculation has one double in it the whole thing gets done in double precision. To get round it you have to put f after the constants, ie:
   pi += x / (2.0f*(float)i-1.0f);
I am getting 675ms for 100000 iterations (3.1416058540), although I have removed the display driver code.

robtillaart

reminds me of another PI tester that gives an indication of the quality of the random generator;

throw a dart on a square board with a (maximized) circle on it. The chance it is in the circle is PI/4

Code: [Select]
//
//    FILE: pi.pde
//  AUTHOR: Rob Tillaart
//    DATE: 2011
//
// PUPROSE: approx pi by 'darting' randomly
//
float pi = 0;
long in = 0;
long out = 0;

int x = 0;
int y = 0;
int xx = 0;
int yy = 0;

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

void loop()
{
  x = y; //random(0,101);
  xx = yy;
  y = random(0,101);
  yy = y * y;
  if (xx + yy <= 10000) in++;
  out++;
  if ((out % 10000) == 0) Serial.println(4.0 * in / out, 7);
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

securd

#5
Dec 24, 2012, 12:08 am Last Edit: Dec 24, 2012, 03:46 am by Coding Badly Reason: 1
Hi Stimmer,
That was it -- thank you!  The new benchmark numbers, with the LED blink and display logic enabled:

Using float precision, 100,000 iterations with display:
 Mega: 6249 ms
 Due:  821 ms (Due is about 7.5x faster)

Using double precision, 100,000 iterations with display:
 Mega: 6249 ms (obviously still using float)
 Due: 1780 ms (actually using double)

(Using double precision on the Due, 8 million iterations will yield about 8 digits of precision in 143,000 ms.  Wow, Newton converges slowly for high levels of precision...)

# of trials = 8000000
Estimate of pi = 3.1415927786
Time: 143102 ms


Below is the code utilizing float, and runs on Mega and Due for apples-to-apples performance comparison:

Code: [Select]
//
// Pi_2
//
// Steve Curd
// December 2012
//
// This program approximates pi utilizing the Newton's approximation.  It quickly
// converges on the first 5-6 digits of precision, but converges verrrry slowly
// after that.  For example, it takes over a million iterations to get to 7-8
// significant digits.
//
// For demonstration purposes, drives a JY-LKM1638 display module to show the
// approximated value after each 1,000 iterations, and toggles the pin13 LED for a
// visual "sign of life".
//
// I wrote this to evaluate the performance difference between the 8-bit Arduino Mega,
// and the 32-bit Arduino Due.
//
// Benchmark results for 100,000 iterations (pi accurate to 5 significant digits):
//   Mega: 6249 ms
//   Due: 821 ms (Due is about 7.5x faster)
//
// 1638 display module connections:
// VCC -> 3.3v
// GND -> GND
// DIO -> Pin 8
// CLK -> Pin 9
// STB0 -> Pin 7
//
//

#define ITERATIONS 100000L    // number of iterations
#define FLASH 1000            // blink LED every 1000 iterations

#include <TM1638.h>           // include the display library

// TM1638 module(DIO, CLK, STB0)
TM1638 module(8, 9, 7);

void setup() {
 pinMode(13, OUTPUT);        // set the LED up to blink every 1000 iterations
 Serial.begin(57600);
}

void loop() {
 
 unsigned long start, time;
 unsigned long niter=ITERATIONS;
 int LEDcounter = 0;
 boolean alternate = false;
 unsigned long i, count=0;
 float x = 1.0;
 float temp, pi=1.0;


 Serial.print("Beginning ");
 Serial.print(niter);
 Serial.println(" iterations...");
 Serial.println();
 
 start = millis();  
 for ( i = 2; i < niter; i++) {
   x *= -1.0;
   pi += x / (2.0f*(float)i-1.0f);
   if (LEDcounter++ > FLASH) {
     LEDcounter = 0;
     if (alternate) {
       digitalWrite(13, HIGH);
       alternate = false;
     } else {
       digitalWrite(13, LOW);
       alternate = true;
     }
     temp = 40000000.0 * pi;
     module.setDisplayToDecNumber( temp, 0x80);
   }
 }
 time = millis() - start;
 
 pi = pi * 4.0;

 Serial.print("# of trials = ");
 Serial.println(niter);
 Serial.print("Estimate of pi = ");
 Serial.println(pi, 10);
 
 Serial.print("Time: "); Serial.print(time); Serial.println(" ms");
 
 delay(10000);
}



Moderator edit: [code] [/code] tags added.

decrux

Cool project,
maybe adding something that measures the RAM in use would enrich your benchmark.
Greetings

Go Up