xref: /btstack/test/maths/sqrt_test.cpp (revision 1d3bd1e51ca491d6783233c8d7431c44f06daa5a)
1*1d3bd1e5SMatthias Ringwald #include <math.h>
2*1d3bd1e5SMatthias Ringwald #include <sys/time.h>
3*1d3bd1e5SMatthias Ringwald #include <stdio.h>
4*1d3bd1e5SMatthias Ringwald #include <stdlib.h>
5*1d3bd1e5SMatthias Ringwald 
6*1d3bd1e5SMatthias Ringwald #include "CppUTest/TestHarness.h"
7*1d3bd1e5SMatthias Ringwald #include "CppUTest/CommandLineTestRunner.h"
8*1d3bd1e5SMatthias Ringwald 
9*1d3bd1e5SMatthias Ringwald static struct timeval init_tv;
10*1d3bd1e5SMatthias Ringwald 
11*1d3bd1e5SMatthias Ringwald union {
12*1d3bd1e5SMatthias Ringwald     int i;
13*1d3bd1e5SMatthias Ringwald     float x;
14*1d3bd1e5SMatthias Ringwald } u;
15*1d3bd1e5SMatthias Ringwald 
16*1d3bd1e5SMatthias Ringwald // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
17*1d3bd1e5SMatthias Ringwald // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation
sqrt1(const float x)18*1d3bd1e5SMatthias Ringwald float sqrt1(const float x){
19*1d3bd1e5SMatthias Ringwald     u.x = x;
20*1d3bd1e5SMatthias Ringwald     u.i = (1<<29) + (u.i >> 1) - (1<<22);
21*1d3bd1e5SMatthias Ringwald 
22*1d3bd1e5SMatthias Ringwald     // Two Babylonian Steps (simplified from:)
23*1d3bd1e5SMatthias Ringwald     // u.x = 0.5f * (u.x + x/u.x);
24*1d3bd1e5SMatthias Ringwald     // u.x = 0.5f * (u.x + x/u.x);
25*1d3bd1e5SMatthias Ringwald     u.x =       u.x + x/u.x;
26*1d3bd1e5SMatthias Ringwald     u.x = 0.25f*u.x + x/u.x;
27*1d3bd1e5SMatthias Ringwald 
28*1d3bd1e5SMatthias Ringwald     return u.x;
29*1d3bd1e5SMatthias Ringwald }
30*1d3bd1e5SMatthias Ringwald 
31*1d3bd1e5SMatthias Ringwald // Algorithm: Log base 2 approximation and Newton's Method
sqrt3(const float x)32*1d3bd1e5SMatthias Ringwald float sqrt3(const float x){
33*1d3bd1e5SMatthias Ringwald     u.x = x;
34*1d3bd1e5SMatthias Ringwald     u.i = (1<<29) + (u.i >> 1) - (1<<22);
35*1d3bd1e5SMatthias Ringwald     return u.x;
36*1d3bd1e5SMatthias Ringwald }
37*1d3bd1e5SMatthias Ringwald 
sqrt2(const float n)38*1d3bd1e5SMatthias Ringwald float sqrt2(const float n) {
39*1d3bd1e5SMatthias Ringwald     /*using n itself as initial approximation => improve */
40*1d3bd1e5SMatthias Ringwald     float x = n;
41*1d3bd1e5SMatthias Ringwald     float y = 1;
42*1d3bd1e5SMatthias Ringwald     float e = 0.001; /* e decides the accuracy level*/
43*1d3bd1e5SMatthias Ringwald     while(x - y > e){
44*1d3bd1e5SMatthias Ringwald         x = (x + y)/2;
45*1d3bd1e5SMatthias Ringwald         y = n/x;
46*1d3bd1e5SMatthias Ringwald     }
47*1d3bd1e5SMatthias Ringwald     return x;
48*1d3bd1e5SMatthias Ringwald }
49*1d3bd1e5SMatthias Ringwald 
get_time_ms(void)50*1d3bd1e5SMatthias Ringwald static uint32_t get_time_ms(void){
51*1d3bd1e5SMatthias Ringwald     struct timeval tv;
52*1d3bd1e5SMatthias Ringwald     gettimeofday(&tv, NULL);
53*1d3bd1e5SMatthias Ringwald     uint32_t time_ms = (uint32_t)((tv.tv_sec  - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
54*1d3bd1e5SMatthias Ringwald     return time_ms;
55*1d3bd1e5SMatthias Ringwald }
56*1d3bd1e5SMatthias Ringwald 
57*1d3bd1e5SMatthias Ringwald static int values_len = 100000;
58*1d3bd1e5SMatthias Ringwald 
TEST_GROUP(SqrtTest)59*1d3bd1e5SMatthias Ringwald TEST_GROUP(SqrtTest){
60*1d3bd1e5SMatthias Ringwald     void setup(void){
61*1d3bd1e5SMatthias Ringwald     }
62*1d3bd1e5SMatthias Ringwald 
63*1d3bd1e5SMatthias Ringwald     void test_method(float (*my_sqrt)(const float x)){
64*1d3bd1e5SMatthias Ringwald         int i, j;
65*1d3bd1e5SMatthias Ringwald         float precision = 0;
66*1d3bd1e5SMatthias Ringwald         int ta = 0;
67*1d3bd1e5SMatthias Ringwald         int te = 0;
68*1d3bd1e5SMatthias Ringwald 
69*1d3bd1e5SMatthias Ringwald         for (j=0; j<100; j++){
70*1d3bd1e5SMatthias Ringwald             for (i=0; i<values_len; i++){
71*1d3bd1e5SMatthias Ringwald                 int t1 = get_time_ms();
72*1d3bd1e5SMatthias Ringwald                 float expected = sqrt(i);
73*1d3bd1e5SMatthias Ringwald                 int t2 = get_time_ms();
74*1d3bd1e5SMatthias Ringwald                 float actual = my_sqrt(i);
75*1d3bd1e5SMatthias Ringwald                 int t3 = get_time_ms();
76*1d3bd1e5SMatthias Ringwald                 te += t2 - t1;
77*1d3bd1e5SMatthias Ringwald                 ta += t3 - t2;
78*1d3bd1e5SMatthias Ringwald                 precision += fabs(expected - actual);
79*1d3bd1e5SMatthias Ringwald             }
80*1d3bd1e5SMatthias Ringwald         }
81*1d3bd1e5SMatthias Ringwald         printf("Precision: %f, Time: (%d, %d)ms\n", precision/values_len, te, ta);
82*1d3bd1e5SMatthias Ringwald     }
83*1d3bd1e5SMatthias Ringwald };
84*1d3bd1e5SMatthias Ringwald 
TEST(SqrtTest,Sqrt1)85*1d3bd1e5SMatthias Ringwald TEST(SqrtTest, Sqrt1){
86*1d3bd1e5SMatthias Ringwald     printf("\nsqrt1: ");
87*1d3bd1e5SMatthias Ringwald     test_method(sqrt1);
88*1d3bd1e5SMatthias Ringwald }
89*1d3bd1e5SMatthias Ringwald 
TEST(SqrtTest,Sqrt2)90*1d3bd1e5SMatthias Ringwald TEST(SqrtTest, Sqrt2){
91*1d3bd1e5SMatthias Ringwald     printf("\nsqrt2: ");
92*1d3bd1e5SMatthias Ringwald     test_method(sqrt2);
93*1d3bd1e5SMatthias Ringwald }
94*1d3bd1e5SMatthias Ringwald 
TEST(SqrtTest,Sqrt3)95*1d3bd1e5SMatthias Ringwald TEST(SqrtTest, Sqrt3){
96*1d3bd1e5SMatthias Ringwald     printf("\nsqrt3: ");
97*1d3bd1e5SMatthias Ringwald     test_method(sqrt3);
98*1d3bd1e5SMatthias Ringwald }
99*1d3bd1e5SMatthias Ringwald 
main(int argc,const char * argv[])100*1d3bd1e5SMatthias Ringwald int main (int argc, const char * argv[]){
101*1d3bd1e5SMatthias Ringwald     return CommandLineTestRunner::RunAllTests(argc, argv);
102*1d3bd1e5SMatthias Ringwald }
103*1d3bd1e5SMatthias Ringwald 
104*1d3bd1e5SMatthias Ringwald // TODO: check http://www.embedded.com/electronics-blogs/programmer-s-toolbox/4219659/Integer-Square-Roots