Explorar o código

HPCC-16923 Added new funtions Std.Math.FMod and Std.Math.FMatch

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman %!s(int64=8) %!d(string=hai) anos
pai
achega
ee3b4ed6e5

+ 30 - 0
ecllibrary/std/Math.ecl

@@ -10,6 +10,8 @@ REAL8 Nan() : eclrtl,pure,include,library='eclrtl',entrypoint='rtlCreateRealNull
 BOOLEAN IsInfinite(REAL8 value) : eclrtl,pure,include,library='eclrtl',entrypoint='rtlIsInfinite';
 BOOLEAN IsNaN(REAL8 value) : eclrtl,pure,include,library='eclrtl',entrypoint='rtlIsNaN';
 BOOLEAN IsFinite(REAL8 value) : eclrtl,pure,include,library='eclrtl',entrypoint='rtlIsFinite';
+REAL8 fmod(REAL8 numer, REAL8 denom, UNSIGNED1 dbz) : eclrtl,pure,include,library='eclrtl',entrypoint='rtlFMod';
+BOOLEAN fmatch(REAL8 a, REAL8 b, REAL8 epsilon = 0.0) : eclrtl,pure,include,library='eclrtl',entrypoint='rtlFMatch';
     END;
 
 EXPORT Math := MODULE
@@ -52,4 +54,32 @@ EXPORT BOOLEAN isNaN(REAL8 val) := rtl.isNaN(val);
 
 EXPORT BOOLEAN isFinite(REAL8 val) := rtl.isFinite(val);
 
+/**
+ * Returns the floating-point remainder of numer/denom (rounded towards zero).
+ * If denom is zero, the result depends on the -fdivideByZero flag:
+ *   'zero' or unset: return zero.
+ *   'nan': return a non-signalling NaN value
+ *   'fail': throw an exception
+ * 
+ * @param numer           The numerator.
+ * @param denom           The numerator.
+ */
+
+EXPORT REAL8 FMod(REAL8 numer, REAL8 denom) := 
+  rtl.FMod(numer, denom,
+    CASE(__DEBUG__('divideByZero'),
+      'nan'=>2,
+      'fail'=>3,
+      1));
+
+/**
+ * Returns whether two floating point values are the same, within margin of error epsilon.
+ * 
+ * @param a           The first value.
+ * @param b           The second value.
+ * @param epsilon     The allowable margin of error.
+ */
+
+EXPORT BOOLEAN FMatch(REAL8 a, REAL8 b, REAL8 epsilon=0.0) := rtl.FMatch(a, b, epsilon);
+
 END;

+ 15 - 0
rtl/eclrtl/eclrtl.cpp

@@ -4245,6 +4245,21 @@ ECLRTL_API double rtlASin(double x, byte dbz)
     return asin(x);
 }
 
+ECLRTL_API double rtlFMod(double numer, double denom, byte dbz)
+{
+    if (!denom)
+        return rtlInvalidArgument((DBZaction) dbz, "FMOD", denom);
+    return fmod(numer, denom);
+}
+
+ECLRTL_API bool rtlFMatch(double a, double b, double epsilon)
+{
+    if (isnan(a) || isnan(b))
+        return false;
+    return fabs(a-b) <= epsilon;
+}
+
+
 //---------------------------------------------------------------------------
 
 ECLRTL_API bool rtlIsValidReal(unsigned size, const void * data)

+ 3 - 0
rtl/eclrtl/eclrtl.hpp

@@ -600,6 +600,9 @@ ECLRTL_API double rtlLog10(double x, byte dbz = DBZzero);
 ECLRTL_API double rtlSqrt(double x, byte dbz = DBZzero);
 ECLRTL_API double rtlACos(double x, byte dbz = DBZzero);
 ECLRTL_API double rtlASin(double x, byte dbz = DBZzero);
+ECLRTL_API double rtlFMod(double numer, double denom, byte dbz = DBZzero);
+
+ECLRTL_API bool rtlFMatch(double a, double b, double epsilon);
 
 ECLRTL_API bool rtlIsValidReal(unsigned size, const void * data);
 ECLRTL_API double rtlCreateRealNull();

+ 4 - 4
testing/regress/ecl/key/zerodivide1.xml

@@ -56,19 +56,19 @@
  <Row><Result_19>fmod(1.0, 0.0) = </Result_19></Row>
 </Dataset>
 <Dataset name='Result 20'>
- <Row><Result_20>0</Result_20></Row>
+ <Row><Result_20>nan</Result_20></Row>
 </Dataset>
 <Dataset name='Result 21'>
- <Row><Result_21>0</Result_21></Row>
+ <Row><Result_21>nan</Result_21></Row>
 </Dataset>
 <Dataset name='Result 22'>
  <Row><Result_22>fmod(5.3, 2.0) = </Result_22></Row>
 </Dataset>
 <Dataset name='Result 23'>
- <Row><Result_23>1</Result_23></Row>
+ <Row><Result_23>1.3</Result_23></Row>
 </Dataset>
 <Dataset name='Result 24'>
- <Row><Result_24>1</Result_24></Row>
+ <Row><Result_24>1.3</Result_24></Row>
 </Dataset>
 <Dataset name='Result 25'>
  <Row><Result_25>acos(2) = </Result_25></Row>

+ 4 - 4
testing/regress/ecl/key/zerodivide2.xml

@@ -56,19 +56,19 @@
  <Row><Result_19>fmod(1.0, 0.0) = </Result_19></Row>
 </Dataset>
 <Dataset name='Result 20'>
- <Row><Result_20>0</Result_20></Row>
+ <Row><Result_20>0.0</Result_20></Row>
 </Dataset>
 <Dataset name='Result 21'>
- <Row><Result_21>0</Result_21></Row>
+ <Row><Result_21>0.0</Result_21></Row>
 </Dataset>
 <Dataset name='Result 22'>
  <Row><Result_22>fmod(5.3, 2.0) = </Result_22></Row>
 </Dataset>
 <Dataset name='Result 23'>
- <Row><Result_23>1</Result_23></Row>
+ <Row><Result_23>1.3</Result_23></Row>
 </Dataset>
 <Dataset name='Result 24'>
- <Row><Result_24>1</Result_24></Row>
+ <Row><Result_24>1.3</Result_24></Row>
 </Dataset>
 <Dataset name='Result 25'>
  <Row><Result_25>acos(2) = </Result_25></Row>

+ 3 - 0
testing/regress/ecl/key/zerodivide3.xml

@@ -16,3 +16,6 @@
 <Dataset name='Result 6'>
  <Row><Result_6>128.0</Result_6></Row>
 </Dataset>
+<Dataset name='Result 7'>
+ <Row><Result_7>129.0</Result_7></Row>
+</Dataset>

+ 4 - 2
testing/regress/ecl/zerodivide1.ecl

@@ -15,6 +15,8 @@
     limitations under the License.
 ############################################################################## */
 
+IMPORT Std.Math;
+
 #option ('divideByZero', 'nan');
 
 zero := nofold(0.0);
@@ -27,7 +29,7 @@ zero := nofold(0.0);
 'log(-1) = '; ln(-1.0); ln(zero - 1.0);
 'sqrt(-1) = '; sqrt(-1.0); sqrt(zero - 1.0);
 '1/0 = '; 1.0/0.0; 1.0 / zero;
-'fmod(1.0, 0.0) = '; 1.0 % 0.0; 1.0 % zero;
-'fmod(5.3, 2.0) = '; 5.3 % 2.0; 5.3 % (zero+2.0);
+'fmod(1.0, 0.0) = '; Math.FMod(1.0, 0.0); Math.FMod(1.0, zero);
+'fmod(5.3, 2.0) = '; Math.FMod(5.3, 2.0); Math.FMod(5.3, (zero+2.0));
 'acos(2) = '; acos(2.0); acos(2.0 + zero);
 'asin(2) = '; asin(2.0); asin(2.0 + zero);

+ 3 - 2
testing/regress/ecl/zerodivide2.ecl

@@ -15,6 +15,7 @@
     limitations under the License.
 ############################################################################## */
 
+IMPORT Std.Math;
 #option ('divideByZero', 'zero');
 
 zero := nofold(0.0);
@@ -27,7 +28,7 @@ zero := nofold(0.0);
 'log(-1) = '; ln(-1.0); ln(zero - 1.0);
 'sqrt(-1) = '; sqrt(-1.0); sqrt(zero - 1.0);
 '1/0 = '; 1.0/0.0; 1.0 / zero;
-'fmod(1.0, 0.0) = '; 1.0 % 0.0; 1.0 % zero;
-'fmod(5.3, 2.0) = '; 5.3 % 2.0; 5.3 % (zero+2.0);
+'fmod(1.0, 0.0) = '; Math.FMod(1.0, 0.0); Math.FMod(1.0, zero);
+'fmod(5.3, 2.0) = '; Math.FMod(5.3, 2.0); Math.FMod(5.3, (zero+2.0));
 'acos(2) = '; acos(2.0); acos(2.0 + zero);
 'asin(2) = '; asin(2.0); asin(2.0 + zero);

+ 2 - 0
testing/regress/ecl/zerodivide3.ecl

@@ -15,6 +15,7 @@
     limitations under the License.
 ############################################################################## */
 
+IMPORT Std.Math;
 #option ('divideByZero', 'fail');
 
 zero := nofold(0.0);
@@ -25,3 +26,4 @@ catch(sqrt(zero - 1.0), 125);
 catch(1.0 / zero, 126);
 catch(acos(2.0 + zero), 127);
 catch(asin(2.0 + zero), 128);
+catch(Math.FMod(1.0, zero), 129);