Alternative implementations of standard functions/approaches - page 14 1...7891011121314 New comment amrali 2023.04.20 01:31 #131 fxsaber #: Thanks. But this. PS Slow. Also, this has round-off erros. void OnStart() { Print(MyNormalizeDoubleSlow(1.89, 2) == 1.89); // false Print(MyNormalizeDoubleSlow(1.143, 2) == 1.14); // false } Edit: This function avoid a lot of corner cases (very fast + accurate): //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double MyNormalizeDouble(const double value, const int digits) { static const double Powers[]= {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8}; double pwr = Powers[MathMin(digits, 8)]; //--- return Round((value * pwr) * (1 + DBL_EPSILON)) / pwr; } //+------------------------------------------------------------------+ //| Fast ceil, floor, and round using arithmetic operators. | //+------------------------------------------------------------------+ long Ceil( double v) { long k=(long)v; return k + (v > k); } long Floor(double v) { long k=(long)v; return k - (v < k); } long Round(double v) { return (long)((v < 0) ? v - 0.5 : v + 0.5); } long Trunc(double v) { return (long)v; } fxsaber 2023.04.24 16:01 #132 amrali #: This function avoid a lot of corner cases (very fast + accurate): Speeded it up a bit. double MyNormalizeDouble(const double value, const int digits) { static const double Powers[]= {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8}; static const double Powers2[]= {1e0 * (1 + DBL_EPSILON), 1e1 * (1 + DBL_EPSILON), 1e2 * (1 + DBL_EPSILON), 1e3 * (1 + DBL_EPSILON), 1e4 * (1 + DBL_EPSILON), 1e5 * (1 + DBL_EPSILON), 1e6 * (1 + DBL_EPSILON), 1e7 * (1 + DBL_EPSILON), 1e8 * (1 + DBL_EPSILON)}; // return Round(value * Powers2[digits]) / Powers[digits]; return (long)((value > 0) ? value * Powers2[digits] + 0.5 : value * Powers2[digits] - 0.5) / Powers[digits]; //--- } Faster than the NormalizeDouble function by 20%. amrali 2023.04.24 23:34 #133 fxsaber #: Speeded it up a bit. Faster than the NormalizeDouble function by 20%. Yes, that's an accurate algorithm ( than your first one) to round without round-off errors. But, you use two lookup operations. For ceil and floor, you will need 3 lookup tables! Anyway, a little cleaner: return (long)((value > 0 ? 0.5 : -0.5) + value * Powers2[digits]) / Powers[digits]; Edit: Another idea instead of lookup table for exact powers of ten, you could use the "Exponentiation by squaring (Binary exponentiation) algorithm". This is a lot faster than MathPow(), but it is slower than the lookup table method. //+------------------------------------------------------------------+ //| Exponentiation by Squaring (Binary exponentiation) | //+------------------------------------------------------------------+ // https://stackoverflow.com/a/101613 double fast_power(double base, int exponent) { double result = 1.0; for (;;) { if ((exponent & 1) == 1) result *= base; if ((exponent >>= 1) == 0) break; base *= base; } return result; } double MyNormalizeDouble(const double value, const int digits) { double pwr = fast_power(10, digits); return Round((value * pwr) * (1 + DBL_EPSILON)) / pwr; } Weights of an EMA Speed of execution of Imprecise double number calculation 1...7891011121314 New comment
Thanks. But this.
PS Slow.
Also, this has round-off erros.
Edit:
This function avoid a lot of corner cases (very fast + accurate):
This function avoid a lot of corner cases (very fast + accurate):
Speeded it up a bit.
Faster than the NormalizeDouble function by 20%.
Speeded it up a bit.
Faster than the NormalizeDouble function by 20%.
Yes, that's an accurate algorithm ( than your first one) to round without round-off errors.
But, you use two lookup operations. For ceil and floor, you will need 3 lookup tables!
Anyway, a little cleaner:
Edit:
Another idea instead of lookup table for exact powers of ten, you could use the "Exponentiation by squaring (Binary exponentiation) algorithm".
This is a lot faster than MathPow(), but it is slower than the lookup table method.