View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus;
23  
24  import org.hipparchus.random.RandomGenerator;
25  import org.hipparchus.random.Well1024a;
26  import org.hipparchus.random.Well19937a;
27  import org.hipparchus.util.FastMath;
28  import org.hipparchus.util.FieldSinCos;
29  import org.hipparchus.util.FieldSinhCosh;
30  import org.hipparchus.util.MathArrays;
31  import org.hipparchus.util.SinCos;
32  import org.junit.jupiter.api.Assertions;
33  import org.junit.jupiter.api.Test;
34  
35  import java.util.function.DoubleFunction;
36  
37  import static org.junit.jupiter.api.Assertions.assertEquals;
38  import static org.junit.jupiter.api.Assertions.assertTrue;
39  
40  public abstract class CalculusFieldElementAbstractTest<T extends CalculusFieldElement<T>> {
41  
42      protected abstract T build(double x);
43  
44      @Test
45      public void testNewInstance() {
46          // GIVEN
47          final double realZero = 0.;
48          final T expectedZero = build(realZero);
49          // WHEN
50          final T actualZero = expectedZero.newInstance(realZero);
51          // THEN
52          assertEquals(expectedZero.getReal(), actualZero.getReal(), 0.);
53      }
54  
55      @Test
56      public void testAddField() {
57          for (double x = -3; x < 3; x += 0.2) {
58              for (double y = -3; y < 3; y += 0.2) {
59                  checkRelative(x + y, build(x).add(build(y)));
60              }
61          }
62      }
63  
64      @Test
65      public void testAddDouble() {
66          for (double x = -3; x < 3; x += 0.2) {
67              for (double y = -3; y < 3; y += 0.2) {
68                  checkRelative(x + y, build(x).add(y));
69              }
70          }
71      }
72  
73      @Test
74      public void testSubtractField() {
75          for (double x = -3; x < 3; x += 0.2) {
76              for (double y = -3; y < 3; y += 0.2) {
77                  checkRelative(x - y, build(x).subtract(build(y)));
78              }
79          }
80      }
81  
82      @Test
83      public void testSubtractDouble() {
84          for (double x = -3; x < 3; x += 0.2) {
85              for (double y = -3; y < 3; y += 0.2) {
86                  checkRelative(x - y, build(x).subtract(y));
87              }
88          }
89      }
90  
91      @Test
92      public void testMultiplyField() {
93          for (double x = -3; x < 3; x += 0.2) {
94              for (double y = -3; y < 3; y += 0.2) {
95                  checkRelative(x * y, build(x).multiply(build(y)));
96              }
97          }
98      }
99  
100     @Test
101     public void testMultiplyDouble() {
102         for (double x = -3; x < 3; x += 0.2) {
103             for (double y = -3; y < 3; y += 0.2) {
104                 checkRelative(x * y, build(x).multiply(y));
105             }
106         }
107     }
108 
109     @Test
110     public void testMultiplyInt() {
111         for (double x = -3; x < 3; x += 0.2) {
112             for (int y = -10; y < 10; y += 1) {
113                 checkRelative(x * y, build(x).multiply(y));
114             }
115         }
116     }
117 
118     @Test
119     public void testSquare() {
120         for (double x = -3; x < 3; x += 0.2) {
121             checkRelative(x * x, build(x).square());
122         }
123     }
124 
125     @Test
126     public void testDivideField() {
127         for (double x = -3; x < 3; x += 0.2) {
128             for (double y = -3; y < 3; y += 0.2) {
129                 checkRelative(x / y, build(x).divide(build(y)));
130             }
131         }
132     }
133 
134     @Test
135     public void testDivideDouble() {
136         for (double x = -3; x < 3; x += 0.2) {
137             for (double y = -3; y < 3; y += 0.2) {
138                     checkRelative(x / y, build(x).divide(y));
139             }
140         }
141     }
142 
143     @Test
144     public void testToDegrees() {
145         for (double x = -0.9; x < 0.9; x += 0.05) {
146             checkRelative(FastMath.toDegrees(x), build(x).toDegrees());
147         }
148     }
149 
150     @Test
151     public void testToRadians() {
152         for (double x = -0.9; x < 0.9; x += 0.05) {
153             checkRelative(FastMath.toRadians(x), build(x).toRadians());
154         }
155     }
156 
157     @Test
158     public void testCos() {
159         for (double x = -0.9; x < 0.9; x += 0.05) {
160             checkRelative(FastMath.cos(x), build(x).cos());
161         }
162     }
163 
164     @Test
165     public void testAcos() {
166         for (double x = -0.9; x < 0.9; x += 0.05) {
167             checkRelative(FastMath.acos(x), build(x).acos());
168         }
169     }
170 
171     @Test
172     public void testSin() {
173         for (double x = -0.9; x < 0.9; x += 0.05) {
174             checkRelative(FastMath.sin(x), build(x).sin());
175         }
176     }
177 
178     @Test
179     public void testAsin() {
180         for (double x = -0.9; x < 0.9; x += 0.05) {
181             checkRelative(FastMath.asin(x), build(x).asin());
182         }
183     }
184 
185     @Test
186     public void testSinCos() {
187         for (double x = -0.9; x < 0.9; x += 0.05) {
188             FieldSinCos<T> sinCos = build(x).sinCos();
189             checkRelative(FastMath.sin(x), sinCos.sin());
190             checkRelative(FastMath.cos(x), sinCos.cos());
191         }
192     }
193 
194     @Test
195     public void testSinCosNaN() {
196         FieldSinCos<T> sinCos = build(Double.NaN).sinCos();
197         assertTrue(sinCos.sin().isNaN());
198         assertTrue(sinCos.cos().isNaN());
199     }
200 
201     @Test
202     public void testSinCosSum() {
203         final RandomGenerator random = new Well19937a(0x4aab62a42c9eb940L);
204         for (int i = 0; i < 10000; ++i) {
205             final double alpha  = 10.0 * (2.0 * random.nextDouble() - 1.0);
206             final double beta   = 10.0 * (2.0 * random.nextDouble() - 1.0);
207             final T      alphaT = build(alpha);
208             final T      betaT  = build(beta);
209             final SinCos scSum = SinCos.sum(FastMath.sinCos(alpha), FastMath.sinCos(beta));
210             final FieldSinCos<T> scSumT = FieldSinCos.sum(alphaT.sinCos(), betaT.sinCos());
211             checkRelative(scSum.sin(), scSumT.sin());
212             checkRelative(scSum.cos(), scSumT.cos());
213         }
214     }
215 
216     @Test
217     public void testSinCosdifference() {
218         final RandomGenerator random = new Well19937a(0x589aaf49471b03d5L);
219         for (int i = 0; i < 10000; ++i) {
220             final double alpha  = 10.0 * (2.0 * random.nextDouble() - 1.0);
221             final double beta   = 10.0 * (2.0 * random.nextDouble() - 1.0);
222             final T      alphaT = build(alpha);
223             final T      betaT  = build(beta);
224             final SinCos scDifference = SinCos.difference(FastMath.sinCos(alpha), FastMath.sinCos(beta));
225             final FieldSinCos<T> scDifferenceT = FieldSinCos.difference(alphaT.sinCos(), betaT.sinCos());
226             checkRelative(scDifference.sin(), scDifferenceT.sin());
227             checkRelative(scDifference.cos(), scDifferenceT.cos());
228         }
229     }
230 
231     @Test
232     public void testTan() {
233         for (double x = -0.9; x < 0.9; x += 0.05) {
234             checkRelative(FastMath.tan(x), build(x).tan());
235         }
236     }
237 
238     @Test
239     public void testAtan() {
240         for (double x = -0.9; x < 0.9; x += 0.05) {
241             checkRelative(FastMath.atan(x), build(x).atan());
242         }
243     }
244 
245     @Test
246     public void testAtan2() {
247         for (double x = -3; x < 3; x += 0.2) {
248             for (double y = -3; y < 3; y += 0.2) {
249                 checkRelative(FastMath.atan2(y, x), build(y).atan2(build(x)));
250             }
251         }
252     }
253 
254     @Test
255     public void testAtan2SpecialCases() {
256         checkRelative(FastMath.atan2(+0.0, +0.0), build(+0.0).atan2(build(+0.0)));
257         checkRelative(FastMath.atan2(-0.0, +0.0), build(-0.0).atan2(build(+0.0)));
258         checkRelative(FastMath.atan2(+0.0, -0.0), build(+0.0).atan2(build(-0.0)));
259         checkRelative(FastMath.atan2(-0.0, -0.0), build(-0.0).atan2(build(-0.0)));
260     }
261 
262     @Test
263     public void testCosh() {
264         for (double x = -0.9; x < 0.9; x += 0.05) {
265             checkRelative(FastMath.cosh(x), build(x).cosh());
266         }
267     }
268 
269     @Test
270     public void testAcosh() {
271         for (double x = 1.1; x < 5.0; x += 0.05) {
272             checkRelative(FastMath.acosh(x), build(x).acosh());
273         }
274     }
275 
276     @Test
277     public void testSinh() {
278         for (double x = -0.9; x < 0.9; x += 0.05) {
279             checkRelative(FastMath.sinh(x), build(x).sinh());
280         }
281     }
282 
283     @Test
284     public void testAsinh() {
285         for (double x = -0.9; x < 0.9; x += 0.05) {
286             checkRelative(FastMath.asinh(x), build(x).asinh());
287         }
288     }
289 
290     @Test
291     public void testSinhCosh() {
292         for (double x = -0.9; x < 0.9; x += 0.05) {
293             FieldSinhCosh<T> sinhCosh = build(x).sinhCosh();
294             checkRelative(FastMath.sinh(x), sinhCosh.sinh());
295             checkRelative(FastMath.cosh(x), sinhCosh.cosh());
296         }
297     }
298 
299     @Test
300     public void testSinhCoshNaN() {
301         FieldSinhCosh<T> sinhCosh = build(Double.NaN).sinhCosh();
302         assertTrue(sinhCosh.sinh().isNaN());
303         assertTrue(sinhCosh.cosh().isNaN());
304     }
305 
306     @Test
307     public void testTanh() {
308         for (double x = -0.9; x < 0.9; x += 0.05) {
309             checkRelative(FastMath.tanh(x), build(x).tanh());
310         }
311     }
312 
313     @Test
314     public void testAtanh() {
315         for (double x = -0.9; x < 0.9; x += 0.05) {
316             checkRelative(FastMath.atanh(x), build(x).atanh());
317         }
318     }
319 
320     @Test
321     public void testSqrt() {
322         for (double x = 0.01; x < 0.9; x += 0.05) {
323             checkRelative(FastMath.sqrt(x), build(x).sqrt());
324         }
325     }
326 
327     @Test
328     public void testCbrt() {
329         for (double x = -0.9; x < 0.9; x += 0.05) {
330             checkRelative(FastMath.cbrt(x), build(x).cbrt());
331         }
332     }
333 
334     @Test
335     public void testHypot() {
336         for (double x = -3; x < 3; x += 0.2) {
337             for (double y = -3; y < 3; y += 0.2) {
338                 checkRelative(FastMath.hypot(x, y), build(x).hypot(build(y)));
339             }
340         }
341     }
342 
343     @Test
344     public void testHypotSpecialCases() {
345         assertTrue(Double.isNaN(build(Double.NaN).hypot(build(0)).getReal()));
346         assertTrue(Double.isNaN(build(0).hypot(build(Double.NaN)).getReal()));
347         assertEquals(Double.POSITIVE_INFINITY, build(Double.POSITIVE_INFINITY).hypot(build(0)).getReal(), 1.0);
348         assertEquals(Double.POSITIVE_INFINITY, build(Double.NEGATIVE_INFINITY).hypot(build(0)).getReal(), 1.0);
349         assertEquals(Double.POSITIVE_INFINITY, build(Double.POSITIVE_INFINITY).hypot(build(Double.NaN)).getReal(), 1.0);
350         assertEquals(Double.POSITIVE_INFINITY, build(Double.NEGATIVE_INFINITY).hypot(build(Double.NaN)).getReal(), 1.0);
351         assertEquals(Double.POSITIVE_INFINITY, build(0).hypot(build(Double.POSITIVE_INFINITY)).getReal(), 1.0);
352         assertEquals(Double.POSITIVE_INFINITY, build(0).hypot(build(Double.NEGATIVE_INFINITY)).getReal(), 1.0);
353         assertEquals(Double.POSITIVE_INFINITY, build(Double.NaN).hypot(build(Double.POSITIVE_INFINITY)).getReal(), 1.0);
354         assertEquals(Double.POSITIVE_INFINITY, build(Double.NaN).hypot(build(Double.NEGATIVE_INFINITY)).getReal(), 1.0);
355     }
356 
357     @Test
358     public void testRootN() {
359         for (double x = -0.9; x < 0.9; x += 0.05) {
360             for (int n = 1; n < 5; ++n) {
361                 if (x < 0) {
362                     if (n % 2 == 1) {
363                         checkRelative(-FastMath.pow(-x, 1.0 / n), build(x).rootN(n));
364                     }
365                 } else {
366                     checkRelative(FastMath.pow(x, 1.0 / n), build(x).rootN(n));
367                 }
368             }
369         }
370     }
371 
372     @Test
373     public void testPowField() {
374         for (double x = -0.9; x < 0.9; x += 0.05) {
375             for (double y = 0.1; y < 4; y += 0.2) {
376                 checkRelative(FastMath.pow(x, y), build(x).pow(build(y)));
377             }
378         }
379     }
380 
381     @Test
382     public void testPowDouble() {
383         for (double x = -0.9; x < 0.9; x += 0.05) {
384             for (double y = 0.1; y < 4; y += 0.2) {
385                 checkRelative(FastMath.pow(x, y), build(x).pow(y));
386             }
387             checkRelative(FastMath.pow(x, 0.0), build(x).pow(0.0));
388         }
389     }
390 
391     @Test
392     public void testPowInt() {
393         for (double x = -0.9; x < 0.9; x += 0.05) {
394             for (int n = 0; n < 5; ++n) {
395                 checkRelative(FastMath.pow(x, n), build(x).pow(n));
396             }
397         }
398     }
399 
400     @Test
401     public void testExp() {
402         for (double x = -0.9; x < 0.9; x += 0.05) {
403             checkRelative(FastMath.exp(x), build(x).exp());
404         }
405     }
406 
407     @Test
408     public void testExpm1() {
409         for (double x = -0.9; x < 0.9; x += 0.05) {
410             checkRelative(FastMath.expm1(x), build(x).expm1());
411         }
412     }
413 
414     @Test
415     public void testLog() {
416         for (double x = 0.01; x < 0.9; x += 0.05) {
417             checkRelative(FastMath.log(x), build(x).log());
418         }
419     }
420 
421     @Test
422     public void testLog1p() {
423         for (double x = -0.9; x < 0.9; x += 0.05) {
424             checkRelative(FastMath.log1p(x), build(x).log1p());
425         }
426     }
427 
428     @Test
429     public void testLog10() {
430         for (double x = -0.9; x < 0.9; x += 0.05) {
431             checkRelative(FastMath.log10(x), build(x).log10());
432         }
433     }
434 
435     @Test
436     public void testScalb() {
437         for (double x = -0.9; x < 0.9; x += 0.05) {
438             for (int n = -100; n < 100; ++n) {
439                 checkRelative(FastMath.scalb(x, n), build(x).scalb(n));
440             }
441         }
442     }
443 
444     @Test
445     public void testUlp() {
446         final RandomGenerator random = new Well19937a(0x36d4f8862421e0e4L);
447         for (int i = -300; i < 300; ++i) {
448             final double x = FastMath.scalb(2.0 * random.nextDouble() - 1.0, i);
449             assertTrue(FastMath.ulp(x) >= build(x).ulp().getReal());
450         }
451     }
452 
453     @Test
454     public void testCeil() {
455         for (double x = -0.9; x < 0.9; x += 0.05) {
456             checkRelative(FastMath.ceil(x), build(x).ceil());
457         }
458     }
459 
460     @Test
461     public void testFloor() {
462         for (double x = -0.9; x < 0.9; x += 0.05) {
463             checkRelative(FastMath.floor(x), build(x).floor());
464         }
465     }
466 
467     @Test
468     public void testRint() {
469         for (double x = -0.9; x < 0.9; x += 0.05) {
470             checkRelative(FastMath.rint(x), build(x).rint());
471         }
472     }
473 
474     @Test
475     public void testRemainderField() {
476         for (double x = -3; x < 3; x += 0.2) {
477             for (double y = -3; y < 3; y += 0.2) {
478                 checkRelative(FastMath.IEEEremainder(x, y), build(x).remainder(build(y)));
479             }
480         }
481     }
482 
483     @Test
484     public void testRemainderDouble() {
485         for (double x = -3; x < 3; x += 0.2) {
486             for (double y = -3.2; y < 3.2; y += 0.25) {
487                 checkRelative(FastMath.IEEEremainder(x, y), build(x).remainder(y));
488             }
489         }
490     }
491 
492     @Test
493     public void testCopySignField() {
494         for (double x = -3; x < 3; x += 0.2) {
495             for (double y = -3; y < 3; y += 0.2) {
496                 checkRelative(FastMath.copySign(x, y), build(x).copySign(build(y)));
497             }
498         }
499     }
500 
501     @Test
502     public void testCopySignDouble() {
503         for (double x = -3; x < 3; x += 0.2) {
504             for (double y = -3; y < 3; y += 0.2) {
505                 checkRelative(FastMath.copySign(x, y), build(x).copySign(y));
506             }
507         }
508     }
509 
510     @Test
511     public void testCopySignSpecialField() {
512 
513         assertEquals(-2.0, build(-2.0).copySign(build(-5.0)).getReal(),                     1.0e-10);
514         assertEquals(-2.0, build(+2.0).copySign(build(-5.0)).getReal(),                     1.0e-10);
515         assertEquals(+2.0, build(-2.0).copySign(build(+5.0)).getReal(),                     1.0e-10);
516         assertEquals(+2.0, build(+2.0).copySign(build(+5.0)).getReal(),                     1.0e-10);
517         assertEquals(-2.0, build(-2.0).copySign(build(Double.NEGATIVE_INFINITY)).getReal(), 1.0e-10);
518         assertEquals(-2.0, build(+2.0).copySign(build(Double.NEGATIVE_INFINITY)).getReal(), 1.0e-10);
519         assertEquals(+2.0, build(-2.0).copySign(build(Double.POSITIVE_INFINITY)).getReal(), 1.0e-10);
520         assertEquals(+2.0, build(+2.0).copySign(build(Double.POSITIVE_INFINITY)).getReal(), 1.0e-10);
521         assertEquals(+2.0, build(-2.0).copySign(build(Double.NaN)).getReal(),               1.0e-10);
522         assertEquals(+2.0, build(-2.0).copySign(build(Double.NaN)).getReal(),               1.0e-10);
523         assertEquals(+2.0, build(-2.0).copySign(build(-Double.NaN)).getReal(),              1.0e-10);
524         assertEquals(+2.0, build(-2.0).copySign(build(-Double.NaN)).getReal(),              1.0e-10);
525         assertEquals(-2.0, build(-2.0).copySign(build(-0.0)).getReal(),                     1.0e-10);
526         assertEquals(-2.0, build(+2.0).copySign(build(-0.0)).getReal(),                     1.0e-10);
527         assertEquals(+2.0, build(-2.0).copySign(build(+0.0)).getReal(),                     1.0e-10);
528         assertEquals(+2.0, build(+2.0).copySign(build(+0.0)).getReal(),                     1.0e-10);
529 
530         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(build(-5.0))).getReal(),                     1.0e-10);
531         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(build(-5.0))).getReal(),                     1.0e-10);
532         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(+5.0))).getReal(),                     1.0e-10);
533         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(build(+5.0))).getReal(),                     1.0e-10);
534         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(build(Double.NEGATIVE_INFINITY))).getReal(), 1.0e-10);
535         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(build(Double.NEGATIVE_INFINITY))).getReal(), 1.0e-10);
536         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(Double.POSITIVE_INFINITY))).getReal(), 1.0e-10);
537         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(build(Double.POSITIVE_INFINITY))).getReal(), 1.0e-10);
538         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(Double.NaN))).getReal(),               1.0e-10);
539         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(Double.NaN))).getReal(),               1.0e-10);
540         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(-Double.NaN))).getReal(),              1.0e-10);
541         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(-Double.NaN))).getReal(),              1.0e-10);
542         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(build(-0.0))).getReal(),                     1.0e-10);
543         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(build(-0.0))).getReal(),                     1.0e-10);
544         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(build(+0.0))).getReal(),                     1.0e-10);
545         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(build(+0.0))).getReal(),                     1.0e-10);
546 
547     }
548 
549     @Test
550     public void testCopySignSpecialDouble() {
551 
552         assertEquals(-2.0, build(-2.0).copySign(-5.0).getReal(),                     1.0e-10);
553         assertEquals(-2.0, build(+2.0).copySign(-5.0).getReal(),                     1.0e-10);
554         assertEquals(+2.0, build(-2.0).copySign(+5.0).getReal(),                     1.0e-10);
555         assertEquals(+2.0, build(+2.0).copySign(+5.0).getReal(),                     1.0e-10);
556         assertEquals(-2.0, build(-2.0).copySign(Double.NEGATIVE_INFINITY).getReal(), 1.0e-10);
557         assertEquals(-2.0, build(+2.0).copySign(Double.NEGATIVE_INFINITY).getReal(), 1.0e-10);
558         assertEquals(+2.0, build(-2.0).copySign(Double.POSITIVE_INFINITY).getReal(), 1.0e-10);
559         assertEquals(+2.0, build(+2.0).copySign(Double.POSITIVE_INFINITY).getReal(), 1.0e-10);
560         assertEquals(+2.0, build(-2.0).copySign(Double.NaN).getReal(),               1.0e-10);
561         assertEquals(+2.0, build(-2.0).copySign(Double.NaN).getReal(),               1.0e-10);
562         assertEquals(+2.0, build(-2.0).copySign(-Double.NaN).getReal(),              1.0e-10);
563         assertEquals(+2.0, build(-2.0).copySign(-Double.NaN).getReal(),              1.0e-10);
564         assertEquals(-2.0, build(-2.0).copySign(-0.0).getReal(),                     1.0e-10);
565         assertEquals(-2.0, build(+2.0).copySign(-0.0).getReal(),                     1.0e-10);
566         assertEquals(+2.0, build(-2.0).copySign(+0.0).getReal(),                     1.0e-10);
567         assertEquals(+2.0, build(+2.0).copySign(+0.0).getReal(),                     1.0e-10);
568 
569         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(-5.0)).getReal(),                     1.0e-10);
570         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(-5.0)).getReal(),                     1.0e-10);
571         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(+5.0)).getReal(),                     1.0e-10);
572         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(+5.0)).getReal(),                     1.0e-10);
573         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(Double.NEGATIVE_INFINITY)).getReal(), 1.0e-10);
574         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(Double.NEGATIVE_INFINITY)).getReal(), 1.0e-10);
575         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(Double.POSITIVE_INFINITY)).getReal(), 1.0e-10);
576         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(Double.POSITIVE_INFINITY)).getReal(), 1.0e-10);
577         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(Double.NaN)).getReal(),               1.0e-10);
578         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(Double.NaN)).getReal(),               1.0e-10);
579         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(-Double.NaN)).getReal(),              1.0e-10);
580         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(-Double.NaN)).getReal(),              1.0e-10);
581         assertEquals(-3.0, build(+3.0).copySign(build(-0.0).copySign(-0.0)).getReal(),                     1.0e-10);
582         assertEquals(-3.0, build(+3.0).copySign(build(+0.0).copySign(-0.0)).getReal(),                     1.0e-10);
583         assertEquals(+3.0, build(+3.0).copySign(build(-0.0).copySign(+0.0)).getReal(),                     1.0e-10);
584         assertEquals(+3.0, build(+3.0).copySign(build(+0.0).copySign(+0.0)).getReal(),                     1.0e-10);
585 
586     }
587 
588     @Test
589     public void testSign() {
590         for (double x = -0.9; x < 0.9; x += 0.05) {
591             checkRelative(FastMath.signum(x), build(x).sign());
592         }
593     }
594 
595     @Test
596     public void testLinearCombinationReference() {
597         doTestLinearCombinationReference(x -> build(x), 5.0e-16, 1.0);
598     }
599 
600     protected void doTestLinearCombinationReference(final DoubleFunction<T> builder,
601                                                     final double toleranceLinearCombination,
602                                                     final double relativeErrorNaiveImplementation) {
603 
604         final T[] a = MathArrays.buildArray(build(0).getField(), 3);
605         a[0] = builder.apply(-1321008684645961.0);
606         a[1] = builder.apply(-5774608829631843.0);
607         a[2] = builder.apply(-7645843051051357.0 / 32.0);
608         final T[] b = MathArrays.buildArray(build(0).getField(), 3);
609         b[0] = builder.apply(-5712344449280879.0 / 16.0);
610         b[1] = builder.apply(-4550117129121957.0 / 16.0);
611         b[2] = builder.apply(8846951984510141.0);
612 
613         final T abSumInline = a[0].linearCombination(a[0], b[0], a[1], b[1], a[2], b[2]);
614         final T abSumArray  = a[0].linearCombination(a, b);
615         final T abNaive     = a[0].multiply(b[0]).add(a[1].multiply(b[1])).add(a[2].multiply(b[2]));
616 
617         assertEquals(abSumInline.getReal(), abSumArray.getReal(), 0);
618         final double reference = -65271563724949.90625;
619         assertEquals(reference, abSumInline.getReal(),
620                             toleranceLinearCombination * FastMath.abs(reference));
621         assertEquals(relativeErrorNaiveImplementation * FastMath.abs(reference),
622                             FastMath.abs(abNaive.subtract(reference).getReal()),
623                             1.0e-3 * relativeErrorNaiveImplementation * FastMath.abs(reference));
624 
625     }
626 
627     @Test
628     public void testLinearCombinationFaFa() {
629         RandomGenerator r = new Well1024a(0xfafaL);
630         for (int i = 0; i < 50; ++i) {
631             double[] aD = generateDouble(r, 10);
632             double[] bD = generateDouble(r, 10);
633             T[] aF      = toFieldArray(aD);
634             T[] bF      = toFieldArray(bD);
635             checkRelative(MathArrays.linearCombination(aD, bD),
636                           aF[0].linearCombination(aF, bF));
637         }
638     }
639 
640     @Test
641     public void testLinearCombinationDaFa() {
642         RandomGenerator r = new Well1024a(0xdafaL);
643         for (int i = 0; i < 50; ++i) {
644             double[] aD = generateDouble(r, 10);
645             double[] bD = generateDouble(r, 10);
646             T[] bF      = toFieldArray(bD);
647             checkRelative(MathArrays.linearCombination(aD, bD),
648                           bF[0].linearCombination(aD, bF));
649         }
650     }
651 
652     @Test
653     public void testLinearCombinationFF2() {
654         RandomGenerator r = new Well1024a(0xff2L);
655         for (int i = 0; i < 50; ++i) {
656             double[] aD = generateDouble(r, 2);
657             double[] bD = generateDouble(r, 2);
658             T[] aF      = toFieldArray(aD);
659             T[] bF      = toFieldArray(bD);
660             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1]),
661                           aF[0].linearCombination(aF[0], bF[0], aF[1], bF[1]));
662         }
663     }
664 
665     @Test
666     public void testLinearCombinationDF2() {
667         RandomGenerator r = new Well1024a(0xdf2L);
668         for (int i = 0; i < 50; ++i) {
669             double[] aD = generateDouble(r, 2);
670             double[] bD = generateDouble(r, 2);
671             T[] bF      = toFieldArray(bD);
672             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1]),
673                           bF[0].linearCombination(aD[0], bF[0], aD[1], bF[1]));
674         }
675     }
676 
677     @Test
678     public void testLinearCombinationFF3() {
679         RandomGenerator r = new Well1024a(0xff3L);
680         for (int i = 0; i < 50; ++i) {
681             double[] aD = generateDouble(r, 3);
682             double[] bD = generateDouble(r, 3);
683             T[] aF      = toFieldArray(aD);
684             T[] bF      = toFieldArray(bD);
685             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1], aD[2], bD[2]),
686                           aF[0].linearCombination(aF[0], bF[0], aF[1], bF[1], aF[2], bF[2]));
687         }
688     }
689 
690     @Test
691     public void testLinearCombinationDF3() {
692         RandomGenerator r = new Well1024a(0xdf3L);
693         for (int i = 0; i < 50; ++i) {
694             double[] aD = generateDouble(r, 3);
695             double[] bD = generateDouble(r, 3);
696             T[] bF      = toFieldArray(bD);
697             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1], aD[2], bD[2]),
698                           bF[0].linearCombination(aD[0], bF[0], aD[1], bF[1], aD[2], bF[2]));
699         }
700     }
701 
702     @Test
703     public void testLinearCombinationFF4() {
704         RandomGenerator r = new Well1024a(0xff4L);
705         for (int i = 0; i < 50; ++i) {
706             double[] aD = generateDouble(r, 4);
707             double[] bD = generateDouble(r, 4);
708             T[] aF      = toFieldArray(aD);
709             T[] bF      = toFieldArray(bD);
710             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1], aD[2], bD[2], aD[3], bD[3]),
711                           aF[0].linearCombination(aF[0], bF[0], aF[1], bF[1], aF[2], bF[2], aF[3], bF[3]));
712         }
713     }
714 
715     @Test
716     public void testLinearCombinationDF4() {
717         RandomGenerator r = new Well1024a(0xdf4L);
718         for (int i = 0; i < 50; ++i) {
719             double[] aD = generateDouble(r, 4);
720             double[] bD = generateDouble(r, 4);
721             T[] bF      = toFieldArray(bD);
722             checkRelative(MathArrays.linearCombination(aD[0], bD[0], aD[1], bD[1], aD[2], bD[2], aD[3], bD[3]),
723                           bF[0].linearCombination(aD[0], bF[0], aD[1], bF[1], aD[2], bF[2], aD[3], bF[3]));
724         }
725     }
726 
727     @Test
728     public void testGetPi() {
729         checkRelative(FastMath.PI, build(-10).getPi());
730     }
731 
732     @Test
733     public void testGetReal() {
734         Assertions.assertEquals( 3.25, build( 3.25).getReal(), 1.0e-15);
735         Assertions.assertEquals(-3.25, build(-3.25).getReal(), 1.0e-15);
736         Assertions.assertTrue(build(Double.NEGATIVE_INFINITY).getReal() < 0);
737         Assertions.assertTrue(Double.isInfinite(build(Double.NEGATIVE_INFINITY).getReal()));
738         Assertions.assertTrue(build(Double.POSITIVE_INFINITY).getReal() > 0);
739         Assertions.assertTrue(Double.isInfinite(build(Double.POSITIVE_INFINITY).getReal()));
740         Assertions.assertTrue(Double.isNaN(build(Double.NaN).getReal()));
741     }
742 
743     @Test
744     public void testGetAddendum() {
745         checkAddendum(build( 3.25));
746         checkAddendum(build(-3.25));
747         checkAddendum(build(Double.NEGATIVE_INFINITY));
748         checkAddendum(build(Double.POSITIVE_INFINITY));
749         checkAddendum(build(Double.NaN));
750     }
751 
752     protected void checkAddendum(final T t) {
753         Assertions.assertEquals(0.0, t.getAddendum().getReal(), 1.0e-15);
754         final T rebuilt = t.getAddendum().add(t.getReal());
755         if (t.isInfinite()) {
756             Assertions.assertTrue(rebuilt.isInfinite());
757             Assertions.assertTrue(t.getReal() * rebuilt.getReal() > 0);
758         } else if (t.isNaN()) {
759             Assertions.assertTrue(rebuilt.isNaN());
760         } else {
761             Assertions.assertEquals(t, rebuilt);
762         }
763     }
764 
765     @Test
766     public void testGetField() {
767         checkRelative(1.0, build(-10).getField().getOne());
768         checkRelative(0.0, build(-10).getField().getZero());
769     }
770 
771     @Test
772     public void testAbs() {
773         for (double x = -0.9; x < 0.9; x += 0.05) {
774             checkRelative(FastMath.abs(x), build(x).abs());
775         }
776     }
777 
778     @Test
779     public void testRound() {
780         for (double x = -0.9; x < 0.9; x += 0.05) {
781             assertEquals(FastMath.round(x), build(x).round());
782         }
783     }
784 
785     protected void checkRelative(double expected, T obtained) {
786         if (Double.isNaN(expected)) {
787             assertEquals(expected, obtained.getReal());
788         } else {
789             assertEquals(expected, obtained.getReal(),
790                                     1.0e-15 * (1 + FastMath.abs(expected)));
791         }
792     }
793 
794     private double[] generateDouble (final RandomGenerator r, int n) {
795         double[] a = new double[n];
796         for (int i = 0; i < n; ++i) {
797             a[i] = r.nextDouble();
798         }
799         return a;
800     }
801 
802     private T[] toFieldArray (double[] a) {
803         T[] f = MathArrays.buildArray(build(0).getField(), a.length);
804         for (int i = 0; i < a.length; ++i) {
805             f[i] = build(a[i]);
806         }
807         return f;
808     }
809 
810 }