mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.2.0 Fraction
This commit is contained in:
parent
32d8399ace
commit
78ec633f1e
@ -6,11 +6,32 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.2.0] - 2024-04-22
|
||||
- removed **Printable** interface, braking change
|
||||
- improve quality of **fractionize()** search
|
||||
- split of integer part before search improves precision.
|
||||
- add support for arrays
|
||||
- default value for constructor (0, 1)
|
||||
- add **fraction_array.ino** + **fraction_sizeof.ino**
|
||||
- add **toString()**
|
||||
- add **isInteger()**
|
||||
- update examples
|
||||
- add **fraction_extensive.ino** test range and accuracy sketch
|
||||
- add **fraction_sqrts.ino** test sketch
|
||||
- add **fraction_fast.ino**, fast determination of fraction with 9900 as denominator.
|
||||
- this is very fast, with an accuracy ~1e-4
|
||||
- add **fraction_full_scan.ino** for a full scan search.
|
||||
- optimized **FractionMediant.ino** determine fraction with mediant.
|
||||
- add **fraction_setDenominator.ino** demo
|
||||
- add **FactionPowers2.ino**, fast determination of fraction with powers of 2.- add examples including tests.
|
||||
- update readme.md
|
||||
|
||||
----
|
||||
|
||||
## [0.1.16] - 2023-11-02
|
||||
- update readme.md
|
||||
- minor edits
|
||||
|
||||
|
||||
## [0.1.15] - 2023-02-02
|
||||
- update GitHub actions
|
||||
- update license 2023
|
||||
|
@ -1,11 +1,12 @@
|
||||
//
|
||||
// FILE: FractionFindSum.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo
|
||||
// DATE: 13-feb-2015
|
||||
// PURPOSE: demo fraction math.
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
|
||||
// Find a sum of fractions that (within accuracy)
|
||||
// adds up to a given fraction.
|
||||
//
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
@ -39,7 +40,7 @@ void findSum(Fraction f)
|
||||
{
|
||||
Fraction z(0, 1);
|
||||
|
||||
Serial.print(f);
|
||||
Serial.print(f.toString());
|
||||
Serial.print(" =\t ");
|
||||
for (long i = 1; i < 10000; i++)
|
||||
{
|
||||
@ -48,7 +49,7 @@ void findSum(Fraction f)
|
||||
{
|
||||
f -= g;
|
||||
z += g;
|
||||
Serial.print(g);
|
||||
Serial.print(g.toString());
|
||||
Serial.print(" + ");
|
||||
}
|
||||
if (f == Fraction(0, 1))
|
||||
@ -57,7 +58,7 @@ void findSum(Fraction f)
|
||||
}
|
||||
}
|
||||
Serial.print("\t => ");
|
||||
Serial.println(z);
|
||||
Serial.println(z.toString());
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
@ -67,5 +68,4 @@ void loop()
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -2,10 +2,10 @@
|
||||
// FILE: FractionMediant.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Find fraction by binary search with mediant.
|
||||
// DATE: 2020-04-21
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// this method is not that fast but it shows a nice application for
|
||||
// the mediant.
|
||||
// This method is not fast but it shows an application for the mediant().
|
||||
// Works for positive values only (for now).
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
@ -26,7 +26,7 @@ void setup()
|
||||
Fraction x = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(x);
|
||||
Serial.println(x.toString());
|
||||
Serial.println(x.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
@ -35,7 +35,7 @@ void setup()
|
||||
Fraction y = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(y);
|
||||
Serial.println(y.toString());
|
||||
Serial.println(y.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
@ -55,7 +55,7 @@ void loop()
|
||||
Serial.println();
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y);
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
@ -70,7 +70,7 @@ void loop()
|
||||
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y);
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
@ -82,27 +82,24 @@ void loop()
|
||||
|
||||
Fraction fractionize(float f)
|
||||
{
|
||||
float acc = 1e-6;
|
||||
float d1 = 0;
|
||||
float d2 = 0;
|
||||
float accuracy = 1e-6;
|
||||
int i;
|
||||
Fraction a(0, 1);
|
||||
Fraction b(9999, 1);
|
||||
Fraction q(f);
|
||||
Fraction b(uint16_t(f) + 1, 1);
|
||||
Fraction c;
|
||||
|
||||
for (int i = 0; i < 500; i++)
|
||||
for (i = 0; i < 500; i++)
|
||||
{
|
||||
Fraction c = Fraction::mediant(a, b); // NOTE middle(a,b) is slower and worse!
|
||||
if ( c.toDouble() < f) a = c;
|
||||
c = Fraction::mediant(a, b); // NOTE middle(a, b) is slower and worse!
|
||||
float t = c.toDouble();
|
||||
if ( t < f) a = c;
|
||||
else b = c;
|
||||
|
||||
d1 = abs(f - a.toDouble());
|
||||
d2 = abs(f - b.toDouble());
|
||||
if (d1 < acc && d2 < acc) break;
|
||||
// check the last found value.
|
||||
if (abs(f - t) < accuracy) break;
|
||||
}
|
||||
if (d1 < d2) return a;
|
||||
return b;
|
||||
Serial.println(i);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
// -- END OF FILE --
|
||||
|
108
libraries/Fraction/examples/FractionPower2/FractionPower2.ino
Normal file
108
libraries/Fraction/examples/FractionPower2/FractionPower2.ino
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// FILE: FractionPower2.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Find fraction with powers of 2.
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// this method is very fast as it calculates a fraction in one step with an accuracy
|
||||
// of 1/8192. Quality is limited due the limited range of denominators.
|
||||
//
|
||||
// a slow variant that adds powers of two is added to show some math.
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
float f = PI;
|
||||
start = micros();
|
||||
Fraction x = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(x.toString());
|
||||
Serial.println(x.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
f = EULER;
|
||||
start = micros();
|
||||
Fraction y = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(y.toString());
|
||||
Serial.println(y.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("done...\n");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float f = random(1000000) * 0.000001;
|
||||
|
||||
// reference
|
||||
start = micros();
|
||||
Fraction y(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.println();
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
|
||||
// mediant method.
|
||||
start = micros();
|
||||
y = fractionize(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
}
|
||||
|
||||
|
||||
Fraction fractionize(float f)
|
||||
{
|
||||
Fraction sum(round(f*8192), 8192);
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
// Slow_fractionize works only for range 0..1
|
||||
Fraction slow_fractionize(float f)
|
||||
{
|
||||
Fraction sum(0, 1);
|
||||
Fraction b(1, 2);
|
||||
|
||||
for (int i = 0; i < 25; i++) // might need less
|
||||
{
|
||||
Fraction tmp = sum + b;
|
||||
if (tmp.toFloat() < f) sum = tmp;
|
||||
b /= 2;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
102
libraries/Fraction/examples/Fraction_fast/Fraction_fast.ino
Normal file
102
libraries/Fraction/examples/Fraction_fast/Fraction_fast.ino
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// FILE: Fraction_fast.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Calculate fraction with well chosen number.
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// This method is very fast as it calculates a fraction in one step.
|
||||
// It uses a default denominator of 9900 which is consists of several
|
||||
// small prime factors, to improve the chance of simplifying.
|
||||
// - very fast
|
||||
// - constant accuracy in the order of 1e-4.
|
||||
// - limited set of denominators after simplifying.
|
||||
// P(9900) = {2, 2, 3, 3, 5, 5, 11}
|
||||
//
|
||||
// other explored options:
|
||||
// P(19800) = {2, 2, 2, 3, 3, 5, 5, 11} (add factor 2 factor)
|
||||
// P(10800) = {2, 2, 2, 2, 3, 3, 3, 5, 5}
|
||||
// P(9240) = {2, 2, 2, 3, 5, 7, 11}
|
||||
// P(13860) = {2, 2, 3, 3, 5, 7, 11}
|
||||
// P(30030) = {2, 3, 5, 7, 11, 13}
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
float f = PI;
|
||||
start = micros();
|
||||
Fraction x = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(x.toString());
|
||||
Serial.println(x.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
f = EULER;
|
||||
start = micros();
|
||||
Fraction y = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(y.toString());
|
||||
Serial.println(y.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("done...\n");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float f = random(1000000) * 0.000001;
|
||||
|
||||
// reference
|
||||
start = micros();
|
||||
Fraction y(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.println();
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
|
||||
// mediant method.
|
||||
start = micros();
|
||||
y = fractionize(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
}
|
||||
|
||||
|
||||
Fraction fractionize(float f)
|
||||
{
|
||||
Fraction value(round(f * 9900), 9900);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,106 @@
|
||||
//
|
||||
// FILE: Fraction_full_scan.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Find fraction by full scan possible values.
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// This method is very slow but it scans the whole range (in fact only half)
|
||||
// for all possible fractions, resulting in very good approximations.
|
||||
// Works for positive values only (for now).
|
||||
//
|
||||
// Takes up to 3 seconds per search on a 16 MHz UNO.
|
||||
// Takes up to 12 milliseconds per search on a 240 MHz ESP32.
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
float f = PI;
|
||||
start = micros();
|
||||
Fraction x = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(x.toString());
|
||||
Serial.println(x.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
f = EULER;
|
||||
start = micros();
|
||||
Fraction y = fractionize(f);
|
||||
stop = micros();
|
||||
Serial.println(stop - start);
|
||||
Serial.println(y.toString());
|
||||
Serial.println(y.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("done...\n");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float f = random(1000000) * 0.000001;
|
||||
|
||||
// reference
|
||||
start = micros();
|
||||
Fraction y(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.println();
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
|
||||
// mediant method.
|
||||
start = micros();
|
||||
y = fractionize(f);
|
||||
stop = micros();
|
||||
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 10);
|
||||
Serial.print("\t");
|
||||
Serial.print(y.toDouble(), 10);
|
||||
Serial.print("\t");
|
||||
Serial.println(f - y.toDouble(), 10);
|
||||
}
|
||||
|
||||
// very very slow but very good.
|
||||
Fraction fractionize(float f)
|
||||
{
|
||||
int best = 1;
|
||||
float smallest = 1.0;
|
||||
// smaller denominators will all be detected as 5000..10000 are multiples.
|
||||
for (int d = 5000; d < 10000; d++)
|
||||
{
|
||||
Fraction frac(f * d + 0.5, d);
|
||||
float tmp = abs(f - frac.toFloat());
|
||||
if ( tmp < smallest)
|
||||
{
|
||||
smallest = tmp;
|
||||
best = d;
|
||||
}
|
||||
}
|
||||
Fraction frac(round(f * best), best);
|
||||
return frac;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -2,7 +2,6 @@
|
||||
// FILE: fractionTest01.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test sketch for fraction math
|
||||
// DATE: 2015-01-25
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
@ -51,14 +50,14 @@ void test_constructor()
|
||||
Serial.print("TIME: \t");
|
||||
Serial.println(stop - start);
|
||||
|
||||
Serial.println(q);
|
||||
Serial.println(a);
|
||||
Serial.println(aa);
|
||||
Serial.println(b);
|
||||
Serial.println(n);
|
||||
Serial.println(p);
|
||||
Serial.println(pi);
|
||||
Serial.println(e);
|
||||
Serial.println(q.toString());
|
||||
Serial.println(a.toString());
|
||||
Serial.println(aa.toString());
|
||||
Serial.println(b.toString());
|
||||
Serial.println(n.toString());
|
||||
Serial.println(p.toString());
|
||||
Serial.println(pi.toString());
|
||||
Serial.println(e.toString());
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +75,7 @@ void test_math()
|
||||
stop = micros();
|
||||
Serial.print("TIME +: \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
|
||||
delay(10);
|
||||
start = micros();
|
||||
@ -84,7 +83,7 @@ void test_math()
|
||||
stop = micros();
|
||||
Serial.print("TIME -: \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
|
||||
delay(10);
|
||||
start = micros();
|
||||
@ -92,7 +91,7 @@ void test_math()
|
||||
stop = micros();
|
||||
Serial.print("TIME *: \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
|
||||
delay(10);
|
||||
start = micros();
|
||||
@ -100,7 +99,7 @@ void test_math()
|
||||
stop = micros();
|
||||
Serial.print("TIME /: \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
}
|
||||
|
||||
|
||||
@ -151,7 +150,7 @@ void test_misc()
|
||||
stop = micros();
|
||||
Serial.print("TIME mediant(): \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
|
||||
delay(10);
|
||||
start = micros();
|
||||
@ -159,7 +158,7 @@ void test_misc()
|
||||
stop = micros();
|
||||
Serial.print("TIME middle(): \t");
|
||||
Serial.println(stop - start);
|
||||
Serial.println(a);
|
||||
Serial.println(a.toString());
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,51 @@
|
||||
//
|
||||
// FILE: Fraction_setDenominator.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Calculate fraction with well chosen number.
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Fraction pi(PI);
|
||||
Fraction appr = Fraction::setDenominator(pi, 32);
|
||||
Serial.println(pi.toString());
|
||||
Serial.println(pi.toDouble(), 10);
|
||||
Serial.println(appr.toString());
|
||||
Serial.println(appr.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Fraction ee(EULER);
|
||||
appr = Fraction::setDenominator(ee, 32);
|
||||
Serial.println(ee.toString());
|
||||
Serial.println(ee.toDouble(), 10);
|
||||
Serial.println(appr.toString());
|
||||
Serial.println(appr.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Fraction tt(0.125);
|
||||
appr = Fraction::setDenominator(tt, 32);
|
||||
Serial.println(tt.toString());
|
||||
Serial.println(tt.toDouble(), 10);
|
||||
Serial.println(appr.toString());
|
||||
Serial.println(appr.toDouble(), 10);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("done...\n");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -2,9 +2,7 @@
|
||||
// FILE: fractionExerciser.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo sketch for fraction math
|
||||
// DATE: 2015-03-29
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
@ -88,14 +86,14 @@ int add(int n)
|
||||
{
|
||||
Fraction a(1 + random(9), 1 + random(9));
|
||||
Fraction b(1 + random(9), 1 + random(9));
|
||||
Serial.print(a);
|
||||
Serial.print(a.toString());
|
||||
Serial.print(" + ");
|
||||
Serial.print(b);
|
||||
Serial.print(b.toString());
|
||||
Serial.print(" = ");
|
||||
Fraction c = readFraction();
|
||||
Serial.print(c);
|
||||
Serial.print(c.toString());
|
||||
Serial.print("\t\t");
|
||||
Serial.println(a + b);
|
||||
Serial.println((a + b).toString());
|
||||
|
||||
if (c == a + b ) count++;
|
||||
}
|
||||
@ -111,14 +109,14 @@ int sub(int n)
|
||||
{
|
||||
Fraction a(1 + random(9), 1 + random(9));
|
||||
Fraction b(1 + random(9), 1 + random(9));
|
||||
Serial.print(a);
|
||||
Serial.print(a.toString());
|
||||
Serial.print(" - ");
|
||||
Serial.print(b);
|
||||
Serial.print(b.toString());
|
||||
Serial.print(" = ");
|
||||
Fraction c = readFraction();
|
||||
Serial.print(c);
|
||||
Serial.print(c.toString());
|
||||
Serial.print("\t\t");
|
||||
Serial.println(a - b);
|
||||
Serial.println((a - b).toString());
|
||||
|
||||
if (c == a - b ) count++;
|
||||
}
|
||||
@ -134,14 +132,14 @@ int mul(int n)
|
||||
{
|
||||
Fraction a(1 + random(9), 1 + random(9));
|
||||
Fraction b(1 + random(9), 1 + random(9));
|
||||
Serial.print(a);
|
||||
Serial.print(a.toString());
|
||||
Serial.print(" * ");
|
||||
Serial.print(b);
|
||||
Serial.print(b.toString());
|
||||
Serial.print(" = ");
|
||||
Fraction c = readFraction();
|
||||
Serial.print(c);
|
||||
Serial.print(c.toString());
|
||||
Serial.print("\t\t");
|
||||
Serial.println(a * b);
|
||||
Serial.println((a * b).toString());
|
||||
|
||||
if (c == a * b ) count++;
|
||||
}
|
||||
@ -157,14 +155,14 @@ int div(int n)
|
||||
{
|
||||
Fraction a(1 + random(9), 1 + random(9));
|
||||
Fraction b(1 + random(9), 1 + random(9));
|
||||
Serial.print(a);
|
||||
Serial.print(a.toString());
|
||||
Serial.print(" / ");
|
||||
Serial.print(b);
|
||||
Serial.print(b.toString());
|
||||
Serial.print(" = ");
|
||||
Fraction c = readFraction();
|
||||
Serial.print(c);
|
||||
Serial.print(c.toString());
|
||||
Serial.print("\t\t");
|
||||
Serial.println(a / b);
|
||||
Serial.println((a / b).toString());
|
||||
|
||||
if (c == a / b ) count++;
|
||||
}
|
||||
@ -180,9 +178,9 @@ int equ(int n)
|
||||
{
|
||||
Fraction a(1 + random(9), 1 + random(9));
|
||||
Fraction b(1 + random(9), 1 + random(9));
|
||||
Serial.print(a);
|
||||
Serial.print(a.toString());
|
||||
Serial.print("\t?\t");
|
||||
Serial.print(b);
|
||||
Serial.print(b.toString());
|
||||
|
||||
char c = choice();
|
||||
Serial.print("\t");
|
||||
@ -196,4 +194,4 @@ int equ(int n)
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
// -- END OF FILE --
|
||||
|
@ -2,7 +2,6 @@
|
||||
// FILE: fractionTest01.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test sketch for fraction math
|
||||
// DATE: 2015-01-25
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
@ -17,6 +16,7 @@ Fraction n(0, 5);
|
||||
Fraction p(5, 1);
|
||||
Fraction pi(PI);
|
||||
Fraction e(EULER);
|
||||
Fraction gr(1.6180339887498948482); // golden ratio
|
||||
|
||||
|
||||
void setup()
|
||||
@ -26,16 +26,17 @@ void setup()
|
||||
Serial.println(FRACTION_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Serial.println(a);
|
||||
Serial.println(aa);
|
||||
Serial.println(b);
|
||||
Serial.println(n);
|
||||
Serial.println(p);
|
||||
Serial.println(q);
|
||||
Serial.println(pi);
|
||||
Serial.println(e);
|
||||
Serial.println(Fraction::middle(pi, e));
|
||||
Serial.println(Fraction::mediant(pi, e));
|
||||
Serial.println(a.toString());
|
||||
Serial.println(aa.toString());
|
||||
Serial.println(b.toString());
|
||||
Serial.println(n.toString());
|
||||
Serial.println(p.toString());
|
||||
Serial.println(q.toString());
|
||||
Serial.println(pi.toString());
|
||||
Serial.println(e.toString());
|
||||
Serial.println(Fraction::middle(pi, e).toString());
|
||||
Serial.println(Fraction::mediant(pi, e).toString());
|
||||
Serial.println(gr.toString());
|
||||
Serial.println();
|
||||
|
||||
testPlus();
|
||||
@ -60,12 +61,12 @@ void loop()
|
||||
void testPlus()
|
||||
{
|
||||
Serial.println("testPlus");
|
||||
Serial.println(a + b);
|
||||
Serial.println((a + b).toString());
|
||||
Fraction c = a + b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
c = a;
|
||||
c += b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
@ -74,12 +75,12 @@ void testPlus()
|
||||
void testMin()
|
||||
{
|
||||
Serial.println("testMin");
|
||||
Serial.println(a - b);
|
||||
Serial.println((a - b).toString());
|
||||
Fraction c = a - b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
c = a;
|
||||
c -= b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
@ -88,12 +89,12 @@ void testMin()
|
||||
void testMul()
|
||||
{
|
||||
Serial.println("testMul");
|
||||
Serial.println(a * b);
|
||||
Serial.println((a * b).toString());
|
||||
Fraction c = a * b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
c = a;
|
||||
c *= b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
@ -102,12 +103,12 @@ void testMul()
|
||||
void testDiv()
|
||||
{
|
||||
Serial.println("testDiv");
|
||||
Serial.println(a / b);
|
||||
Serial.println((a / b).toString());
|
||||
Fraction c = a / b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
c = a;
|
||||
c /= b;
|
||||
Serial.println(c);
|
||||
Serial.println(c.toString());
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
@ -175,5 +176,4 @@ void testGE()
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -0,0 +1,45 @@
|
||||
//
|
||||
// FILE: fraction_array.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test fraction memory
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// (0.1.16) On AVR it uses 10 bytes per element, where 8 were expected.
|
||||
// (0.2.0) solved this
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
Fraction arr[50];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.print("FRACTION_LIB_VERSION: ");
|
||||
Serial.println(FRACTION_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
for ( int n = 0; n < 33; n++)
|
||||
{
|
||||
arr[n] = Fraction(n, 32);
|
||||
Serial.print(n);
|
||||
Serial.print("\t");
|
||||
Serial.print(arr[n].toString());
|
||||
Serial.print("\t");
|
||||
Serial.print(arr[n].toFloat(), 7);
|
||||
Serial.print("\t");
|
||||
Serial.println(n / 32.0, 7);
|
||||
}
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,81 @@
|
||||
//
|
||||
// FILE: fraction_extensive_test.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: reasonable extensive fraction test
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
// step size to test, typical 100000
|
||||
// for 100.000 tests
|
||||
// - AVR UNO 16 MHz takes ~500 seconds at 115200 baud
|
||||
// - ESP32 240 MHz takes ~400 seconds at 115200 baud
|
||||
// - ESP32 240 MHz takes ~85 seconds at 500000 baud
|
||||
|
||||
|
||||
const uint32_t N = 100000;
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
uint32_t start, stop;
|
||||
float maxError = 0;
|
||||
uint32_t pos = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// NOTE BAUDRATE!
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.print("FRACTION_LIB_VERSION: ");
|
||||
Serial.println(FRACTION_LIB_VERSION);
|
||||
Serial.println();
|
||||
delay(100);
|
||||
|
||||
|
||||
Fraction pi(PI);
|
||||
Serial.println(pi.toString());
|
||||
delay(1000);
|
||||
|
||||
start = millis();
|
||||
|
||||
for (uint32_t n = 100; n <= N; n++)
|
||||
{
|
||||
float g = n * (1.0 / N);
|
||||
Fraction frac( g );
|
||||
float f = frac.toFloat();
|
||||
|
||||
// find the maxError so far.
|
||||
float relError = abs(abs(f / g) - 1);
|
||||
if (relError > maxError)
|
||||
{
|
||||
maxError = relError;
|
||||
pos = n;
|
||||
}
|
||||
Serial.print(n);
|
||||
Serial.print("\t");
|
||||
Serial.print(g, 6);
|
||||
Serial.print("\t");
|
||||
Serial.print(f, 6);
|
||||
Serial.print("\t");
|
||||
Serial.print(100 * relError, 3); // as percentage
|
||||
Serial.print("\t");
|
||||
Serial.print(frac.toString());
|
||||
Serial.println();
|
||||
}
|
||||
stop = millis();
|
||||
Serial.println();
|
||||
Serial.print("MILLIS: ");
|
||||
Serial.println(stop - start);
|
||||
Serial.print("MAXERR: ");
|
||||
Serial.println(maxError);
|
||||
Serial.print(" POS: ");
|
||||
Serial.println(pos);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,41 @@
|
||||
//
|
||||
// FILE: fraction_sizeof.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test fraction memory
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
//
|
||||
// On AVR it uses 10 bytes per element, where 8 were expected.
|
||||
//
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
|
||||
Fraction a(0.42);
|
||||
Fraction arr[20];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.print("FRACTION_LIB_VERSION: ");
|
||||
Serial.println(FRACTION_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
arr[19] = a;
|
||||
|
||||
Serial.println(a.toFloat());
|
||||
Serial.print("sizeof: \t");
|
||||
Serial.println(sizeof(a));
|
||||
Serial.println(arr[19].toFloat());
|
||||
Serial.print("sizeof: \t");
|
||||
Serial.println(sizeof(arr));
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,49 @@
|
||||
//
|
||||
// FILE: fraction_sqrts.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: fraction version of first 10000 square roots
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
#include "fraction.h"
|
||||
|
||||
Fraction sqr;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(__FILE__);
|
||||
Serial.print("FRACTION_LIB_VERSION: ");
|
||||
Serial.println(FRACTION_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
for ( int n = 0; n <= 10000; n++)
|
||||
{
|
||||
Fraction sqr( sqrt(n));
|
||||
float f = sqr.toFloat();
|
||||
// test for relative error 1e-5
|
||||
// if (abs((f * f / n) - 1) > 0.00001)
|
||||
{
|
||||
Serial.print(n);
|
||||
Serial.print("\t");
|
||||
Serial.print(sqr.toString());
|
||||
Serial.print("\t\t");
|
||||
Serial.print(sqrt(n), 7);
|
||||
Serial.print("\t\t");
|
||||
Serial.print(f, 7);
|
||||
Serial.print("\t\t");
|
||||
Serial.println(abs((f * f / n) - 1), 7);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: fraction.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.16
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Arduino library to implement a Fraction data type
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
@ -35,7 +35,8 @@ void Fraction::split(float f)
|
||||
// EULER = 1264/465; // 2.2e-6
|
||||
|
||||
// get robust for small values. (effectively zero)
|
||||
if (abs(f) < 0.00001)
|
||||
// as 1/10000 is smallest
|
||||
if (abs(f) < 0.0001)
|
||||
{
|
||||
n = 0;
|
||||
d = 1;
|
||||
@ -47,29 +48,20 @@ void Fraction::split(float f)
|
||||
d = 1;
|
||||
return;
|
||||
}
|
||||
// Normalize to 0.0 ... 1.0
|
||||
|
||||
// handle sign
|
||||
bool negative = f < 0;
|
||||
if (negative) f = -f;
|
||||
|
||||
// TODO investigate different strategy:
|
||||
// intpart = int32_t(f); // strip of the integer part.
|
||||
// f = f - intpart; // determine remainder
|
||||
// determine n, d
|
||||
// n += intpart * d; // add integer part * denominator to fraction.
|
||||
|
||||
bool reciproke = f > 1;
|
||||
if (reciproke) f = 1/f;
|
||||
// strip of the integer part and process only remainder (0.0..1.0)
|
||||
int32_t integerPart = int32_t(f);
|
||||
f = f - integerPart;
|
||||
|
||||
fractionize(f);
|
||||
simplify();
|
||||
|
||||
// denormalize
|
||||
if (reciproke)
|
||||
{
|
||||
int32_t t = n;
|
||||
n = d;
|
||||
d = t;
|
||||
}
|
||||
// add integerPart again, but in units of denominator.
|
||||
n += (integerPart * d);
|
||||
if (negative)
|
||||
{
|
||||
n = -n;
|
||||
@ -83,28 +75,6 @@ Fraction::Fraction(int32_t p, int32_t q) : n(p), d(q)
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
//
|
||||
// PRINTING
|
||||
//
|
||||
size_t Fraction::printTo(Print& p) const
|
||||
{
|
||||
size_t s = 0;
|
||||
// TODO split of sign first
|
||||
//
|
||||
// vs 22/7 => 3_1/7
|
||||
// if (n >= d)
|
||||
// {
|
||||
// s += p.print(n/d, DEC);
|
||||
// s += p.print("_");
|
||||
// }
|
||||
// s += p.print(n%d, DEC);
|
||||
s += p.print(n, DEC);
|
||||
s += p.print('/');
|
||||
s += p.print(d, DEC);
|
||||
return s;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
//
|
||||
@ -250,6 +220,11 @@ Fraction& Fraction::operator /= (const Fraction &c)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
//
|
||||
// CONVERSION and PRINTING
|
||||
//
|
||||
double Fraction::toDouble()
|
||||
{
|
||||
return double(n) / d;
|
||||
@ -262,6 +237,18 @@ float Fraction::toFloat()
|
||||
}
|
||||
|
||||
|
||||
String Fraction::toString()
|
||||
{
|
||||
String s = "(";
|
||||
// if (n < 0) s += "-";
|
||||
s += n;
|
||||
s += "/";
|
||||
s += d;
|
||||
s += ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// fraction is proper if abs(fraction) < 1
|
||||
bool Fraction::isProper()
|
||||
{
|
||||
@ -269,6 +256,13 @@ bool Fraction::isProper()
|
||||
}
|
||||
|
||||
|
||||
// fraction is proper if abs(fraction) < 1
|
||||
bool Fraction::isInteger()
|
||||
{
|
||||
return (d == 1);
|
||||
}
|
||||
|
||||
|
||||
// visualize fraction as an angle in degrees
|
||||
float Fraction::toAngle()
|
||||
{
|
||||
@ -363,7 +357,7 @@ void Fraction::simplify()
|
||||
// in preventing overflow
|
||||
while (q > 10000)
|
||||
{
|
||||
// rounding might need improvement
|
||||
// rounding need improvement
|
||||
p = (p + 5)/10;
|
||||
q = (q + 5)/10;
|
||||
x = gcd(p, q);
|
||||
@ -380,9 +374,16 @@ void Fraction::simplify()
|
||||
// fractionize() - finds the fraction representation of a float
|
||||
// PRE: 0 <= f < 1.0
|
||||
//
|
||||
// minimalistic is fast and small
|
||||
// minimalistic, fast and small accuracy ~1e-4
|
||||
// void Fraction::fractionize(float val)
|
||||
// {
|
||||
// n = round(val * 9900);
|
||||
// d = 9900;
|
||||
// }
|
||||
|
||||
|
||||
//
|
||||
// check for a discussion found later
|
||||
// check for a discussion found later (link is dead)
|
||||
// - http://mathforum.org/library/drmath/view/51886.html
|
||||
// - http://www.gamedev.net/topic/354209-how-do-i-convert-a-decimal-to-a-fraction-in-c/
|
||||
//
|
||||
@ -392,18 +393,24 @@ void Fraction::simplify()
|
||||
// - http://mathforum.org/library/drmath/view/51886.html
|
||||
// (100x) micros()=96048
|
||||
// showed errors for very small values around 0
|
||||
|
||||
|
||||
void Fraction::fractionize(float val)
|
||||
{
|
||||
// find nearest fraction
|
||||
float Precision = 0.0000001;
|
||||
// Fraction low(int(val * 9900), 9900); // "A" = 0/1
|
||||
// Fraction high(int(val * 9240) + 1, 9240); // "B" = 1/1
|
||||
Fraction low(0, 1); // "A" = 0/1
|
||||
Fraction high(1, 1); // "B" = 1/1
|
||||
|
||||
// max 100 iterations
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
float testLow = low.d * val - low.n;
|
||||
float testHigh = high.n - high.d * val;
|
||||
if (testHigh < Precision * high.d)
|
||||
break; // high is answer
|
||||
break; // high is answer
|
||||
|
||||
if (testLow < Precision * low.d)
|
||||
{ // low is answer
|
||||
@ -416,7 +423,7 @@ void Fraction::fractionize(float val)
|
||||
int32_t count = (int32_t)test; // "N"
|
||||
int32_t n = (count + 1) * low.n + high.n;
|
||||
int32_t d = (count + 1) * low.d + high.d;
|
||||
if ((n > 0x8000) || (d > 0x10000))
|
||||
if ((n > 0x8000) || (d > 0x10000)) // 0x8000 0x10000
|
||||
break;
|
||||
high.n = n - low.n; // new "A"
|
||||
high.d = d - low.d;
|
||||
@ -429,7 +436,7 @@ void Fraction::fractionize(float val)
|
||||
int32_t count = (int32_t)test; // "N"
|
||||
int32_t n = low.n + (count + 1) * high.n;
|
||||
int32_t d = low.d + (count + 1) * high.d;
|
||||
if ((n > 0x10000) || (d > 0x10000))
|
||||
if ((n > 0x10000) || (d > 0x10000)) // 0x10000 0x10000
|
||||
break;
|
||||
low.n = n - high.n; // new "A"
|
||||
low.d = d - high.d;
|
||||
|
@ -2,22 +2,22 @@
|
||||
//
|
||||
// FILE: fraction.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.16
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Arduino library to implement a Fraction data type
|
||||
// URL: https://github.com/RobTillaart/Fraction
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define FRACTION_LIB_VERSION (F("0.1.16"))
|
||||
#define FRACTION_LIB_VERSION (F("0.2.0"))
|
||||
|
||||
|
||||
class Fraction: public Printable
|
||||
class Fraction
|
||||
{
|
||||
public:
|
||||
explicit Fraction(double);
|
||||
explicit Fraction(float);
|
||||
Fraction(int32_t, int32_t);
|
||||
Fraction(int32_t = 0, int32_t = 1); // default zero constructor
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit Fraction(int32_t p) : n(p), d(1) {}
|
||||
@ -28,8 +28,6 @@ public:
|
||||
explicit Fraction(uint8_t p) : n(p), d(1) {}
|
||||
Fraction(const Fraction &f) : n(f.n), d(f.d) {}
|
||||
|
||||
size_t printTo(Print& p) const;
|
||||
|
||||
// EQUALITIES
|
||||
bool operator == (const Fraction&);
|
||||
// bool operator == (const float&);
|
||||
@ -53,10 +51,13 @@ public:
|
||||
Fraction& operator *= (const Fraction&);
|
||||
Fraction& operator /= (const Fraction&);
|
||||
|
||||
// CONVERSION
|
||||
// CONVERSION and PRINTING
|
||||
double toDouble();
|
||||
float toFloat();
|
||||
String toString();
|
||||
|
||||
bool isProper(); // abs(f) < 1
|
||||
bool isInteger(); // d == 1
|
||||
float toAngle();
|
||||
|
||||
int32_t nominator();
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/Fraction.git"
|
||||
},
|
||||
"version": "0.1.16",
|
||||
"version": "0.2.0",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
"headers": "fraction.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=Fraction
|
||||
version=0.1.16
|
||||
version=0.2.0
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library to implement a Fraction datatype.
|
||||
|
@ -23,15 +23,68 @@ The code is working with a number of limitations a.o.:
|
||||
- denominator is max 4 digits to keep code for multiply and divide simple
|
||||
- Fractions are not exact, even floats are not exact.
|
||||
- the range of numbers supported is limited.
|
||||
- code is experimental still.
|
||||
- code is experimental.
|
||||
|
||||
That said, the library is useful e.g. to display float numbers as a fraction.
|
||||
From programming point of view the **fractionize(float)** function, converting a double
|
||||
into a fraction is a nice programming problem, fast with a minimal error.
|
||||
From programming point of view the **fractionize(float)** function,
|
||||
converting a double / float into a fraction is a nice programming problem,
|
||||
how to do it fast while minimizing the error.
|
||||
|
||||
In short, use fractions with care otherwise your sketch might get broken ;)
|
||||
|
||||
|
||||
#### Notes on natural order
|
||||
|
||||
Depending on **fractionize(float)** algorithm used the natural order of numbers
|
||||
might be broken.
|
||||
This means that if two floats are very close
|
||||
```
|
||||
float f < float g does not imply Fraction(f) < Fraction(g)
|
||||
float f > float g does not imply Fraction(g) > Fraction(f)
|
||||
```
|
||||
|
||||
The minimalistic **fractionize** keeps the natural order due its simplicity.
|
||||
It does have a lower accuracy as only limited number of denominators are used.
|
||||
This means that if two floats are very close
|
||||
```
|
||||
float f < float g implies Fraction(f) <= Fraction(g)
|
||||
float f > float g implies Fraction(g) >= Fraction(f)
|
||||
```
|
||||
|
||||
|
||||
#### 0.2.0 Breaking change 1
|
||||
|
||||
When testing with the array implementation it became evident that some
|
||||
Fractions were incorrect (not just inaccurate).
|
||||
|
||||
An analysis lead to using reciproke values for fractions larger than 1.
|
||||
By excluding the integerPart the problem looks solved in most cases.
|
||||
For very small values there are still problems as the fraction cannot be determined.
|
||||
|
||||
A test sketch **fraction_extensive.ino** has been added to test all floats
|
||||
with up to five decimals 0.00000 .. 0.99999.
|
||||
Results looking good but it is no proof of correctness or guarantee there
|
||||
are no issues left. In fact the well known fraction for PI = 355/113 is not
|
||||
found in 0.2.0 any more. This will be investigated in the future.
|
||||
|
||||
|
||||
#### 0.2.0 Breaking change 2
|
||||
|
||||
The 0.1.x version implemented the **Printable** interface to allow direct
|
||||
printing of a Fraction object.
|
||||
However it became clear that this costs 2 extra bytes per element, which adds up
|
||||
when creating arrays of fractions.
|
||||
|
||||
So the **Printable** interface is removed and replaced by a **toString()** function.
|
||||
|
||||
```cpp
|
||||
Fraction fr(PI);
|
||||
Serial.print(fr.toString());
|
||||
```
|
||||
|
||||
Fractions can also be printed by using **toFloat()** or **toDouble()**
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
```cpp
|
||||
@ -42,7 +95,7 @@ In short, use fractions with care otherwise your sketch might get broken ;)
|
||||
|
||||
- **explicit Fraction(double)**
|
||||
- **explicit Fraction(float)**
|
||||
- **Fraction(int32_t nominator, int32_t denominator)**
|
||||
- **Fraction(int32_t nominator = 0, int32_t denominator = 1)** Default zero constructor
|
||||
- **explicit Fraction(int32_t p)**
|
||||
- **explicit Fraction(int16_t p)**
|
||||
- **explicit Fraction(int8_t p)**
|
||||
@ -52,17 +105,6 @@ In short, use fractions with care otherwise your sketch might get broken ;)
|
||||
- **Fraction(const Fraction &f)**
|
||||
|
||||
|
||||
#### Printable
|
||||
|
||||
The Fraction library implements the Printable interface, so one can do.
|
||||
|
||||
```cpp
|
||||
Fraction fr(PI);
|
||||
|
||||
Serial.print(fr); // print 355/113
|
||||
```
|
||||
|
||||
|
||||
#### Equalities
|
||||
|
||||
The Fraction library implements ==, !=, >=, >, <, <=
|
||||
@ -70,24 +112,31 @@ The Fraction library implements ==, !=, >=, >, <, <=
|
||||
|
||||
#### Basic Math
|
||||
|
||||
The Fraction library implements, + - * / += -= *= /= and - (negation)
|
||||
The Fraction library implements:
|
||||
- addition: + and +=
|
||||
- subtraction: - and -+
|
||||
- multiplication: \* and \*=
|
||||
- division: / and /=
|
||||
- negation: -
|
||||
|
||||
|
||||
#### Conversion
|
||||
|
||||
- **double toDouble()** idem.
|
||||
- **float toFloat()** idem.
|
||||
- **double toDouble()** converts the fraction to a double.
|
||||
- **float toFloat()** converts the fraction to a float.
|
||||
- **String toString()** converts the fraction to a String.
|
||||
The format is "(n/d)", where n has optionally the sign.
|
||||
- **bool isProper()** absolute value < 1.
|
||||
- **float toAngle()** returns 0..360 degrees.
|
||||
- **int32_t nominator()** idem.
|
||||
- **int32_t denominator()** idem.
|
||||
- **int32_t nominator()** returns the nominator.
|
||||
- **int32_t denominator()** returns the denominator.
|
||||
|
||||
|
||||
#### Miscellaneous (static)
|
||||
|
||||
- **Fraction mediant(const Fraction&, const Fraction&)**
|
||||
- **Fraction middle(const Fraction&, const Fraction&)**
|
||||
- **Fraction setDenominator(const Fraction&, uint16_t)**
|
||||
- **Fraction setDenominator(const Fraction&, uint16_t)** (might be simplified still)
|
||||
|
||||
|
||||
## Use with care
|
||||
@ -104,13 +153,16 @@ The library is reasonably tested. If problems arise please open an issue.
|
||||
|
||||
#### Should
|
||||
|
||||
- investigate the fraction of PI (0.2.0 does not find 355/113)
|
||||
- performance testing
|
||||
- investigate better **fractionize()**
|
||||
- see **fraction_fast.ino** for faster fractionize (price == accuracy)
|
||||
- a good start value ?
|
||||
- depends on nominator / denominator size
|
||||
- **float fractionize()** returns the error.
|
||||
- investigate divide by zero errors
|
||||
- NAN in fraction? => 0/0 ?
|
||||
- INF in fraction? => 1/0 and -1/0?
|
||||
- investigate better **fractionize()**
|
||||
- depends on nom/denom size
|
||||
- returns the error..
|
||||
|
||||
#### Could
|
||||
|
||||
@ -119,6 +171,8 @@ The library is reasonably tested. If problems arise please open an issue.
|
||||
- add famous constants as Fraction e.g
|
||||
- FRAC_PI = 355/113
|
||||
- FRAC_E = 3985/1466
|
||||
- FRAC_GOLDEN_RATIO = (2584/1597)
|
||||
- add parameters to **toString()** to set () and separator?
|
||||
|
||||
#### Wont
|
||||
|
||||
|
@ -44,16 +44,24 @@ unittest_teardown()
|
||||
unittest(test_constructor)
|
||||
{
|
||||
Fraction pi(PI);
|
||||
assertEqual(355, pi.nominator());
|
||||
assertEqual(113, pi.denominator());
|
||||
assertEqualFloat(PI, pi.toFloat(), 0.0001);
|
||||
// what we wished it would find.
|
||||
// assertEqual(355, pi.nominator());
|
||||
// assertEqual(113, pi.denominator());
|
||||
// (15689, 4994)
|
||||
assertFalse(pi.isProper());
|
||||
fprintf(stderr, "PI -> %1.8f\n", pi.toFloat());
|
||||
|
||||
fprintf(stderr, "PI %1.8f\n", PI);
|
||||
fprintf(stderr, "pi %1.8f\n", pi.toFloat());
|
||||
|
||||
Fraction ee(EULER);
|
||||
assertEqual(3985, ee.nominator());
|
||||
assertEqual(1466, ee.denominator());
|
||||
assertEqualFloat(EULER, ee.toFloat(), 0.0001);
|
||||
// what we wished it would find.
|
||||
// assertEqual(3985, ee.nominator());
|
||||
// assertEqual(1466, ee.denominator());
|
||||
// (2721, 1001)
|
||||
assertFalse(ee.isProper());
|
||||
fprintf(stderr, "EULER -> %1.8f\n", ee.toFloat());
|
||||
fprintf(stderr, "EULER %1.8f\n", EULER);
|
||||
fprintf(stderr, "euler %1.8f\n", ee.toFloat());
|
||||
|
||||
Fraction fr(49, 14);
|
||||
assertEqual(7, fr.nominator());
|
||||
|
Loading…
Reference in New Issue
Block a user