Pages: [1]   Go Down
Author Topic: Arduino Due Benchmark - Newton Approximation for Pi  (Read 3931 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 76 times.)
« Last Edit: December 23, 2012, 09:45:00 pm by Coding Badly » Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 506
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
God Member
*****
Karma: 32
Posts: 506
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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 Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Pages: [1]   Go Up
Jump to: