Pages: [1]   Go Down
 Author Topic: Arduino Due Benchmark - Newton Approximation for Pi  (Read 5759 times) 0 Members and 1 Guest are viewing this topic.
Offline
Newbie
Karma: 0
Posts: 3
 « on: December 23, 2012, 02:15:08 pm » Bigger Smaller Reset

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:
//
// 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.
 Arduino_Pi.JPG (112.35 KB, 640x480 - viewed 130 times.) « Last Edit: December 23, 2012, 09:45:00 pm by Coding Badly » Logged

Offline
God Member
Karma: 32
Posts: 507
 « Reply #1 on: December 23, 2012, 02:34:12 pm » Bigger Smaller Reset

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.
 Logged

Offline
Newbie
Karma: 0
Posts: 3
 « Reply #2 on: December 23, 2012, 02:52:30 pm » Bigger Smaller Reset

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.
 Logged

Offline
God Member
Karma: 32
Posts: 507
 « Reply #3 on: December 23, 2012, 03:11:50 pm » Bigger Smaller Reset

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.
 « Last Edit: December 23, 2012, 03:14:20 pm by stimmer » Logged

Global Moderator
Netherlands
Offline
Shannon Member
Karma: 224
Posts: 13917
In theory there is no difference between theory and practice, however in practice there are many...
 « Reply #4 on: December 23, 2012, 04:02:34 pm » Bigger Smaller Reset

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:
//
//    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);
}
 Logged

Rob Tillaart

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

Offline
Newbie
Karma: 0
Posts: 3
 « Reply #5 on: December 23, 2012, 06:08:13 pm » Bigger Smaller Reset

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:
//
// 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.
 « Last Edit: December 23, 2012, 09:46:20 pm by Coding Badly » Logged

Offline
Newbie
Karma: 0
Posts: 15
 « Reply #6 on: December 25, 2012, 11:26:46 am » Bigger Smaller Reset

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

 Pages: [1]   Go Up