1 package org.djunits.value;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.fail;
5
6 import java.lang.reflect.Constructor;
7 import java.lang.reflect.Field;
8 import java.lang.reflect.InvocationTargetException;
9 import java.lang.reflect.Method;
10
11 import org.djunits.unit.Unit;
12 import org.djunits.unit.unitsystem.UnitSystem;
13 import org.djunits.util.ClassUtil;
14 import org.djunits.value.vdouble.scalar.AbstractDoubleScalar;
15 import org.djunits.value.vdouble.scalar.AbstractDoubleScalarAbs;
16 import org.djunits.value.vdouble.scalar.AbstractDoubleScalarRel;
17 import org.djunits.value.vdouble.scalar.DoubleScalar;
18 import org.djunits.value.vdouble.scalar.DoubleScalarInterface;
19 import org.djunits.value.vfloat.scalar.AbstractFloatScalar;
20 import org.djunits.value.vfloat.scalar.AbstractFloatScalarAbs;
21 import org.djunits.value.vfloat.scalar.AbstractFloatScalarRel;
22 import org.djunits.value.vfloat.scalar.FloatScalar;
23 import org.djunits.value.vfloat.scalar.FloatScalarInterface;
24 import org.junit.Assert;
25 import org.junit.Test;
26
27
28
29
30
31
32
33
34
35
36
37
38 public class ScalarOperationsTest
39 {
40
41 public static final String[] CLASSNAMES_ABS = new String[] { "AbsoluteTemperature", "Direction", "Position", "Time" };
42
43
44 public static final String[] CLASSNAMES_ABS_REL = new String[] { "Temperature", "Angle", "Length", "Duration" };
45
46
47 public static final String[] CLASSNAMES_REL = new String[] { "Angle", "Acceleration", "AngleSolid", "Area", "Density",
48 "Dimensionless", "Duration", "ElectricalCharge", "ElectricalCurrent", "ElectricalPotential", "ElectricalResistance",
49 "Energy", "FlowMass", "FlowVolume", "Force", "Frequency", "Length", "LinearDensity", "Mass", "Power", "Pressure",
50 "Speed", "Temperature", "Torque", "Volume" };
51
52
53 public static final String[] CLASSNAMES_MONEY = new String[] { "Money", "MoneyPerArea", "MoneyPerEnergy", "MoneyPerLength",
54 "MoneyPerMass", "MoneyPerDuration", "MoneyPerVolume" };
55
56
57
58
59
60
61
62
63
64
65
66
67 @SuppressWarnings("static-method")
68 @Test
69 public final void scalarOperationsTest() throws NoSuchMethodException, InstantiationException, IllegalAccessException,
70 InvocationTargetException, NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException
71 {
72 doubleOrFloatScalarOperationsTest(true);
73 doubleOrFloatScalarOperationsTest(false);
74 }
75
76
77
78
79
80
81
82
83
84
85
86
87
88 private void doubleOrFloatScalarOperationsTest(final boolean doubleType)
89 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
90 NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException
91 {
92 final String upperType = doubleType ? "Double" : "Float";
93 final String type = upperType.toLowerCase();
94
95 for (int i = 0; i < CLASSNAMES_ABS.length; i++)
96 {
97 String scalarNameAbs = CLASSNAMES_ABS[i];
98 String scalarNameRel = CLASSNAMES_ABS_REL[i];
99 String scalarClassNameAbs = doubleType ? scalarNameAbs : "Float" + scalarNameAbs;
100 String scalarClassNameRel = doubleType ? scalarNameRel : "Float" + scalarNameRel;
101 Class<?> scalarClassAbs = null;
102 Class<?> scalarClassRel = null;
103
104 try
105 {
106 scalarClassAbs = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassNameAbs);
107 }
108 catch (ClassNotFoundException exception)
109 {
110 fail("Class Rel not found for " + upperType + "Scalar class " + "org.djunits.value.v" + type + ".scalar."
111 + scalarClassNameAbs);
112 }
113 try
114 {
115 scalarClassRel = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassNameRel);
116 }
117 catch (ClassNotFoundException exception)
118 {
119 fail("Class Rel not found for " + upperType + "Scalar class " + "org.djunits.value.v" + type + ".scalar."
120 + scalarClassNameRel);
121 }
122 testMethods(scalarClassAbs, true, doubleType);
123 testMethods(scalarClassRel, false, doubleType);
124 }
125
126
127 for (String scalarName : CLASSNAMES_REL)
128 {
129 String scalarClassName = doubleType ? scalarName : "Float" + scalarName;
130 Class<?> scalarClassRel = null;
131 try
132 {
133 scalarClassRel = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassName);
134 }
135 catch (ClassNotFoundException exception)
136 {
137 fail("Class Rel not found for " + upperType + "DoubleScalar class " + "org.djunits.value.v" + type + ".scalar."
138 + scalarClassName);
139 }
140 testMethods(scalarClassRel, false, doubleType);
141 }
142
143
144 for (String scalarName : CLASSNAMES_MONEY)
145 {
146 String scalarClassName = doubleType ? scalarName : "Float" + scalarName;
147 Class<?> scalarClassMoney = null;
148 try
149 {
150 scalarClassMoney = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassName);
151 }
152 catch (ClassNotFoundException exception)
153 {
154 fail("Class Rel not found for " + upperType + "DoubleScalar class " + "org.djunits.value.v" + type + ".scalar."
155 + scalarClassName);
156 }
157 testMethods(scalarClassMoney, false, doubleType);
158 }
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 private void testMethods(final Class<?> scalarClassAbsRel, final boolean isAbs, final boolean doubleType)
175 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
176 NoSuchFieldException, ClassNotFoundException
177 {
178 for (Method method : scalarClassAbsRel.getMethods())
179 {
180 if (method.getName().equals("multiplyBy"))
181 {
182
183 testMultiplyOrDivideMethodAbsRel(scalarClassAbsRel, isAbs, method, true, doubleType);
184 }
185 else if (method.getName().equals("divideBy"))
186 {
187 testMultiplyOrDivideMethodAbsRel(scalarClassAbsRel, isAbs, method, false, doubleType);
188 }
189 }
190 testUnaryMethods(scalarClassAbsRel, isAbs, doubleType);
191 testInterpolateMethod(scalarClassAbsRel, isAbs, doubleType);
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 private void testMultiplyOrDivideMethodAbsRel(final Class<?> scalarClass, final boolean abs, final Method method,
208 final boolean multiply, final boolean doubleType) throws NoSuchMethodException, InstantiationException,
209 IllegalAccessException, InvocationTargetException, NoSuchFieldException
210 {
211 Class<?> relativeOrAbsoluteClass = null;
212 try
213 {
214 relativeOrAbsoluteClass = Class.forName("org.djunits.value." + (abs ? "Absolute" : "Relative"));
215 }
216 catch (ClassNotFoundException exception)
217 {
218 fail("Could not find org.djunits.value.Relative class");
219 }
220 Class<?>[] parTypes = method.getParameterTypes();
221 if (parTypes.length != 1)
222 {
223 fail("DoubleScalar class " + scalarClass.getName() + "." + method.getName() + "() has " + parTypes.length
224 + " parameters, <> 1");
225 }
226 Class<?> parameterClass = parTypes[0];
227 if (parameterClass.toString().equals("double") || parameterClass.toString().equals("float"))
228 {
229
230 return;
231 }
232 if (!relativeOrAbsoluteClass.isAssignableFrom(parameterClass))
233 {
234 System.out.println("abs=" + abs + ", method=" + scalarClass.getName() + "." + method.getName() + " param="
235 + parameterClass.getName());
236 Assert.fail("DoubleScalar class " + scalarClass.getName() + "." + method.getName() + "() has parameter with non-"
237 + relativeOrAbsoluteClass + " class: " + relativeOrAbsoluteClass.getName());
238 }
239
240 Class<?> returnClass = method.getReturnType();
241 if (!relativeOrAbsoluteClass.isAssignableFrom(returnClass))
242 {
243 Assert.fail("DoubleScalar class " + scalarClass.getName()
244 + ".multiplyBy() has return type with non-relative class: " + returnClass.getName());
245 }
246
247
248 String returnSI = getCoefficients(getUnitClass(returnClass));
249 String scalarSI = getCoefficients(getUnitClass(scalarClass));
250 String paramSI = getCoefficients(getUnitClass(parameterClass));
251
252 System.out.println(scalarClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + "."
253 + (multiply ? "multiplyBy" : "divideBy") + "("
254 + parameterClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + ") => "
255 + returnClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + ": " + scalarSI
256 + (multiply ? " * " : " : ") + paramSI + " => " + returnSI);
257
258 Constructor<?> constructor = scalarClass.getConstructor(double.class, getUnitClass(scalarClass));
259 if (abs)
260 {
261 fail("Absolute types should not have a multiply or divide method");
262 AbstractDoubleScalarAbs<?, ?, ?, ?> left = (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(123d,
263 getSIUnitInstance(getUnitClass(scalarClass), abs));
264
265 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
266 AbstractDoubleScalarAbs<?, ?, ?, ?> right = (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(456d,
267 getSIUnitInstance(getUnitClass(parameterClass), abs));
268
269 double expectedValue = multiply ? 123d * 456 : 123d / 456;
270
271 if (multiply)
272 {
273 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "multiplyBy", new Class[] { parameterClass });
274 Object result = multiplyMethod.invoke(left, right);
275 double resultSI = ((AbstractDoubleScalarAbs<?, ?, ?, ?>) result).si;
276 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
277 }
278 else
279 {
280 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divideBy", new Class[] { parameterClass });
281 Object result = divideMethod.invoke(left, right);
282 double resultSI = ((AbstractDoubleScalarAbs<?, ?, ?, ?>) result).si;
283 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
284 }
285 }
286 else
287 {
288 if (doubleType)
289 {
290 AbstractDoubleScalarRel<?, ?> left = (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(123d,
291 getSIUnitInstance(getUnitClass(scalarClass), abs));
292
293 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
294 AbstractDoubleScalarRel<?, ?> right = (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(456d,
295 getSIUnitInstance(getUnitClass(parameterClass), abs));
296
297 double expectedValue = multiply ? 123d * 456 : 123d / 456;
298
299 if (multiply)
300 {
301 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "multiplyBy", new Class[] { parameterClass });
302 Object result = multiplyMethod.invoke(left, right);
303 double resultSI = ((AbstractDoubleScalarRel<?, ?>) result).si;
304 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
305 }
306 else
307 {
308 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divideBy", new Class[] { parameterClass });
309 Object result = divideMethod.invoke(left, right);
310 double resultSI = ((AbstractDoubleScalarRel<?, ?>) result).si;
311 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
312 }
313 AbstractDoubleScalarRel<?, ?> result =
314 multiply ? DoubleScalar.multiply(left, right) : DoubleScalar.divide(left, right);
315
316 String resultCoefficients = result.getUnit().getSICoefficientsString();
317 assertEquals("SI coefficients of result should match expected SI coefficients", resultCoefficients, returnSI);
318 }
319 else
320 {
321 AbstractFloatScalarRel<?, ?> left = (AbstractFloatScalarRel<?, ?>) constructor.newInstance(123f,
322 getSIUnitInstance(getUnitClass(scalarClass), abs));
323
324 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
325 AbstractFloatScalarRel<?, ?> right = (AbstractFloatScalarRel<?, ?>) constructor.newInstance(456f,
326 getSIUnitInstance(getUnitClass(parameterClass), abs));
327
328 float expectedValue = multiply ? 123f * 456 : 123f / 456;
329
330 if (multiply)
331 {
332 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "multiplyBy", new Class[] { parameterClass });
333 Object result = multiplyMethod.invoke(left, right);
334 double resultSI = ((AbstractFloatScalarRel<?, ?>) result).si;
335 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
336 }
337 else
338 {
339 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divideBy", new Class[] { parameterClass });
340 Object result = divideMethod.invoke(left, right);
341 float resultSI = ((AbstractFloatScalarRel<?, ?>) result).si;
342 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
343 }
344 AbstractFloatScalarRel<?, ?> result =
345 multiply ? FloatScalar.multiply(left, right) : FloatScalar.divide(left, right);
346
347 String resultCoefficients = result.getUnit().getSICoefficientsString();
348 assertEquals("SI coefficients of result should match expected SI coefficients", resultCoefficients, returnSI);
349 }
350 }
351 }
352
353
354
355
356
357
358
359
360 private String getCoefficients(final Class<?> clas) throws IllegalAccessException, NoSuchFieldException
361 {
362 if (clas.getName().contains("Money"))
363 {
364
365 for (Field field : clas.getDeclaredFields())
366 {
367 if (field.getType().equals(clas))
368 {
369 return ((Unit<?>) field.get(clas)).getSICoefficientsString();
370 }
371 }
372 return "1";
373 }
374 Field si = clas.getField("SI");
375 Unit<?> u = ((Unit<?>) si.get(clas));
376 String r = u.getSICoefficientsString();
377 return r;
378
379 }
380
381
382
383
384
385
386
387
388
389 private Unit<?> getSIUnitInstance(final Class<?> clas, final boolean isAbs)
390 throws NoSuchFieldException, IllegalAccessException
391 {
392 if (clas.getName().contains("Money"))
393 {
394
395 for (Field field : clas.getDeclaredFields())
396 {
397 if (field.getType().equals(clas))
398 {
399 return ((Unit<?>) field.get(clas));
400 }
401 }
402 return null;
403 }
404 Field si = isAbs ? clas.getField("BASE") : clas.getField("SI");
405 return ((Unit<?>) si.get(clas));
406 }
407
408
409
410
411
412
413 private Class<?> getUnitClass(final Class<?> scalarClass)
414 {
415 Constructor<?>[] constructors = scalarClass.getConstructors();
416 for (Constructor<?> constructor : constructors)
417 {
418 Class<?>[] parTypes = constructor.getParameterTypes();
419 if (parTypes.length == 2 && Unit.class.isAssignableFrom(parTypes[1]))
420 {
421 return parTypes[1];
422 }
423 }
424 Assert.fail("Could not find constructor with one unit for Scalar class " + scalarClass.getName());
425 return null;
426 }
427
428
429
430
431
432
433
434
435 private double verifyAbsRelPrecisionAndExtractSI(final boolean abs, final boolean doubleType, final Object o)
436 {
437 double result = Double.NaN;
438 if (doubleType)
439 {
440 if (!(o instanceof DoubleScalarInterface))
441 {
442 fail("object is not a DoubleScalar");
443 }
444 result = ((AbstractDoubleScalar<?, ?>) o).getSI();
445 }
446 else
447 {
448 if (!(o instanceof FloatScalarInterface))
449 {
450 fail("object is not a FloatScalar");
451 }
452 result = ((AbstractFloatScalar<?, ?>) o).getSI();
453 }
454 if (o instanceof Absolute)
455 {
456 if (!abs)
457 {
458 fail("Result should have been Absolute");
459 }
460 }
461 else if (o instanceof Relative)
462 {
463 if (abs)
464 {
465 fail("Result should have been Relative");
466 }
467 }
468 else
469 {
470 fail("Result is neither Absolute, nor Relative");
471 }
472 return result;
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486 private void testUnaryMethods(final Class<?> scalarClass, final boolean abs, final boolean doubleType)
487 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
488 NoSuchFieldException, ClassNotFoundException
489 {
490 double value = 1.23456;
491 Constructor<?> constructor =
492 scalarClass.getConstructor(doubleType ? double.class : float.class, getUnitClass(scalarClass));
493 Object left;
494 if (doubleType)
495 {
496 left = abs
497 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(value,
498 getSIUnitInstance(getUnitClass(scalarClass), abs))
499 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(value,
500 getSIUnitInstance(getUnitClass(scalarClass), abs));
501
502 Constructor<?>[] constructors = scalarClass.getConstructors();
503 for (Constructor<?> c : constructors)
504 {
505 Class<?>[] parTypes = c.getParameterTypes();
506 if (parTypes.length == 1)
507 {
508 AbstractDoubleScalar<?, ?> newInstance = (AbstractDoubleScalar<?, ?>) c.newInstance(left);
509 assertEquals("Result of constructor should be equal to original", value,
510 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, newInstance), 0.01);
511 }
512 }
513 }
514 else
515 {
516 left = abs
517 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance((float) value,
518 getSIUnitInstance(getUnitClass(scalarClass), abs))
519 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance((float) value,
520 getSIUnitInstance(getUnitClass(scalarClass), abs));
521
522 Constructor<?>[] constructors = scalarClass.getConstructors();
523 for (Constructor<?> c : constructors)
524 {
525 Class<?>[] parTypes = c.getParameterTypes();
526 if (parTypes.length == 1)
527 {
528
529 AbstractFloatScalar<?, ?> newInstance = (AbstractFloatScalar<?, ?>) c.newInstance(left);
530 assertEquals("Result of constructor should be equal to original", value,
531 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, newInstance), 0.01);
532 }
533 }
534 }
535 Object result;
536
537 Method ceil = ClassUtil.resolveMethod(scalarClass, "ceil", new Class[] {});
538 result = ceil.invoke(left);
539 assertEquals("Result of operation", Math.ceil(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
540
541 Method floor = ClassUtil.resolveMethod(scalarClass, "floor", new Class[] {});
542 result = floor.invoke(left);
543 assertEquals("Result of operation", Math.floor(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
544 0.01);
545
546 Method rint = ClassUtil.resolveMethod(scalarClass, "rint", new Class[] {});
547 result = rint.invoke(left);
548 assertEquals("Result of operation", Math.rint(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
549
550 Method round = ClassUtil.resolveMethod(scalarClass, "round", new Class[] {});
551 result = round.invoke(left);
552 assertEquals("Result of operation", Math.round(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
553 0.01);
554
555 if (!abs)
556 {
557 Method methodAbs = ClassUtil.resolveMethod(scalarClass, "abs", new Class[] {});
558 result = methodAbs.invoke(left);
559 assertEquals("Result of operation", Math.abs(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
560 0.01);
561 }
562
563 if (scalarClass.getName().contains("Dimensionless"))
564 {
565 Method asin = ClassUtil.resolveMethod(scalarClass, "asin", new Class[] {});
566 result = asin.invoke(left);
567 assertEquals("Result of operation", Math.asin(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
568 0.01);
569
570 Method acos = ClassUtil.resolveMethod(scalarClass, "acos", new Class[] {});
571 result = acos.invoke(left);
572 assertEquals("Result of operation", Math.acos(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
573 0.01);
574
575 Method atan = ClassUtil.resolveMethod(scalarClass, "atan", new Class[] {});
576 result = atan.invoke(left);
577 assertEquals("Result of operation", Math.atan(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
578 0.01);
579
580 Method cbrt = ClassUtil.resolveMethod(scalarClass, "cbrt", new Class[] {});
581 result = cbrt.invoke(left);
582 assertEquals("Result of operation", Math.cbrt(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
583 0.01);
584
585 Method cos = ClassUtil.resolveMethod(scalarClass, "cos", new Class[] {});
586 result = cos.invoke(left);
587 assertEquals("Result of operation", Math.cos(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
588 0.01);
589
590 Method cosh = ClassUtil.resolveMethod(scalarClass, "cosh", new Class[] {});
591 result = cosh.invoke(left);
592 assertEquals("Result of operation", Math.cosh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
593 0.01);
594
595 Method exp = ClassUtil.resolveMethod(scalarClass, "exp", new Class[] {});
596 result = exp.invoke(left);
597 assertEquals("Result of operation", Math.exp(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
598 0.01);
599
600 Method expm1 = ClassUtil.resolveMethod(scalarClass, "expm1", new Class[] {});
601 result = expm1.invoke(left);
602 assertEquals("Result of operation", Math.expm1(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
603 0.01);
604
605 Method log = ClassUtil.resolveMethod(scalarClass, "log", new Class[] {});
606 result = log.invoke(left);
607 assertEquals("Result of operation", Math.log(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
608 0.01);
609
610 Method log10 = ClassUtil.resolveMethod(scalarClass, "log10", new Class[] {});
611 result = log10.invoke(left);
612 assertEquals("Result of operation", Math.log10(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
613 0.01);
614
615 Method log1p = ClassUtil.resolveMethod(scalarClass, "log1p", new Class[] {});
616 result = log1p.invoke(left);
617 assertEquals("Result of operation", Math.log1p(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
618 0.01);
619
620 Method signum = ClassUtil.resolveMethod(scalarClass, "signum", new Class[] {});
621 result = signum.invoke(left);
622 assertEquals("Result of operation", Math.signum(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
623 0.01);
624
625 Method sin = ClassUtil.resolveMethod(scalarClass, "sin", new Class[] {});
626 result = sin.invoke(left);
627 assertEquals("Result of operation", Math.sin(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
628 0.01);
629
630 Method sinh = ClassUtil.resolveMethod(scalarClass, "sinh", new Class[] {});
631 result = sinh.invoke(left);
632 assertEquals("Result of operation", Math.sinh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
633 0.01);
634
635 Method sqrt = ClassUtil.resolveMethod(scalarClass, "sqrt", new Class[] {});
636 result = sqrt.invoke(left);
637 assertEquals("Result of operation", Math.sqrt(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
638 0.01);
639
640 Method tan = ClassUtil.resolveMethod(scalarClass, "tan", new Class[] {});
641 result = tan.invoke(left);
642 assertEquals("Result of operation", Math.tan(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
643 0.01);
644
645 Method tanh = ClassUtil.resolveMethod(scalarClass, "tanh", new Class[] {});
646 result = tanh.invoke(left);
647 assertEquals("Result of operation", Math.tanh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
648 0.01);
649
650 Method inv = ClassUtil.resolveMethod(scalarClass, "inv", new Class[] {});
651 result = inv.invoke(left);
652 assertEquals("Result of operation", 1 / value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
653
654 Method pow = ClassUtil.resolveMethod(scalarClass, "pow", new Class[] { double.class });
655 result = pow.invoke(left, Math.PI);
656 assertEquals("Result of operation", Math.pow(value, Math.PI),
657 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
658 }
659
660 Object compatibleRight = null;
661
662 if (!scalarClass.getName().contains("Money") && !scalarClass.getName().contains("Dimensionless")
663 && !scalarClass.getName().contains("Temperature") && !scalarClass.getName().contains("Position")
664 && !scalarClass.getName().contains("Time") && !scalarClass.getName().contains("Direction"))
665 {
666
667 Class<?> unitClass = getUnitClass(scalarClass);
668 UnitSystem unitSystem = UnitSystem.SI_DERIVED;
669 Unit<?> referenceUnit;
670
671 Method getUnitMethod = ClassUtil.resolveMethod(scalarClass, "getUnit");
672 referenceUnit = (Unit<?>) getUnitMethod.invoke(left);
673 Constructor<?> unitConstructor =
674 unitClass.getConstructor(String.class, String.class, UnitSystem.class, unitClass, double.class);
675 Object newUnit = unitConstructor.newInstance("7fullName", "7abbr", unitSystem, referenceUnit, 7d);
676
677 if (doubleType)
678 {
679 compatibleRight = abs ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(value, newUnit)
680 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(value, newUnit);
681 }
682 else
683 {
684 compatibleRight = abs ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance((float) value, newUnit)
685 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance((float) value, newUnit);
686 }
687
688 }
689 if (!abs)
690 {
691 Method multiplyBy =
692 ClassUtil.resolveMethod(scalarClass, "multiplyBy", new Class[] { doubleType ? double.class : float.class });
693 result = doubleType ? multiplyBy.invoke(left, Math.PI) : multiplyBy.invoke(left, (float) Math.PI);
694 assertEquals("Result of operation", Math.PI * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
695 0.01);
696
697 Method divideBy =
698 ClassUtil.resolveMethod(scalarClass, "divideBy", new Class[] { doubleType ? double.class : float.class });
699 result = doubleType ? divideBy.invoke(left, Math.PI) : divideBy.invoke(left, (float) Math.PI);
700 assertEquals("Result of operation", value / Math.PI, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
701 0.01);
702
703 Method plus = ClassUtil.resolveMethod(scalarClass, "plus", new Class[] { scalarClass });
704 result = plus.invoke(left, left);
705 assertEquals("Result of operation", value + value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
706 0.01);
707
708 if (null != compatibleRight)
709 {
710 result = plus.invoke(left, compatibleRight);
711 assertEquals("Result of mixed operation", 8 * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
712 0.01);
713
714
715
716 plus = ClassUtil.resolveMethod(scalarClass, "plus", new Class[] { compatibleRight.getClass().getSuperclass() });
717 result = plus.invoke(compatibleRight, left);
718 assertEquals("Result of mixed operation", 8 * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
719 0.01);
720 if (scalarClass.getName().contains("$Rel"))
721 {
722
723 String absScalarClassName = scalarClass.getName().replace("$Rel", "$Abs");
724 Class<?> absScalarClass = Class.forName(absScalarClassName);
725 Constructor<?> absScalarConstructor = absScalarClass.getConstructor(doubleType ? double.class : float.class,
726 getUnitClass(absScalarClass));
727 Object absOperand = null;
728
729 if (doubleType)
730 {
731 absOperand =
732 absScalarConstructor.newInstance(value, getSIUnitInstance(getUnitClass(absScalarClass), true));
733 }
734 else
735 {
736 absOperand = absScalarConstructor.newInstance((float) value,
737 getSIUnitInstance(getUnitClass(absScalarClass), true));
738 }
739
740 plus = ClassUtil.resolveMethod(absScalarClass, "plus", scalarClass);
741 result = plus.invoke(absOperand, left);
742 assertEquals("Result of mixed abs + rel", 2 * value,
743 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
744 Method toAbs = compatibleRight.getClass().getMethod("toAbs");
745 Object absCompatible = toAbs.invoke(compatibleRight);
746 result = plus.invoke(absCompatible, left);
747 assertEquals("Result of mixed compatible abs + rel", 8 * value,
748 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
749
750 plus = ClassUtil.resolveMethod(scalarClass, "plus", absScalarClass);
751 result = plus.invoke(left, absOperand);
752 assertEquals("Result of mixed rel + abs", 2 * value,
753 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
754 result = plus.invoke(left, absCompatible);
755 assertEquals("Result of mixed rel + compatible abs", 8 * value,
756 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
757 }
758 }
759 }
760
761 Method minus = ClassUtil.resolveMethod(scalarClass, "minus", new Class[] { scalarClass });
762 result = minus.invoke(left, left);
763 assertEquals("Result of minus", 0, verifyAbsRelPrecisionAndExtractSI(false, doubleType, result), 0.01);
764 if (null != compatibleRight)
765 {
766 result = minus.invoke(left, compatibleRight);
767 assertEquals("Result of minus with compatible arg for " + left + " and " + compatibleRight, -6 * value,
768 verifyAbsRelPrecisionAndExtractSI(false, doubleType, result), 0.01);
769 }
770 if (scalarClass.getName().contains("$Rel") || scalarClass.getName().contains("$Abs"))
771 {
772
773 String absScalarClassName = scalarClass.getName().replace("$Rel", "$Abs");
774 Class<?> absScalarClass = Class.forName(absScalarClassName);
775 Constructor<?> absScalarConstructor =
776 absScalarClass.getConstructor(doubleType ? double.class : float.class, getUnitClass(absScalarClass));
777 Object absOperand = null;
778
779 if (doubleType)
780 {
781 absOperand = absScalarConstructor.newInstance(value, getSIUnitInstance(getUnitClass(absScalarClass), true));
782 }
783 else
784 {
785 absOperand =
786 absScalarConstructor.newInstance((float) value, getSIUnitInstance(getUnitClass(absScalarClass), true));
787 }
788 minus = ClassUtil.resolveMethod(absScalarClass, "minus", scalarClass);
789 result = minus.invoke(absOperand, left);
790 assertEquals("Result of abs or rel minus rel", 0, verifyAbsRelPrecisionAndExtractSI(!abs, doubleType, result),
791 0.01);
792 if (null != compatibleRight && scalarClass.getName().contains("$Rel"))
793 {
794 Method toAbs = compatibleRight.getClass().getMethod("toAbs");
795 Object absCompatible = toAbs.invoke(compatibleRight);
796 result = minus.invoke(absCompatible, left);
797 assertEquals("Result of compatible abs or rel minus rel", 6 * value,
798 verifyAbsRelPrecisionAndExtractSI(!abs, doubleType, result), 0.01);
799 }
800 }
801 }
802
803
804
805
806
807
808
809
810
811
812
813
814 private void testInterpolateMethod(final Class<?> scalarClass, final boolean abs, final boolean doubleType)
815 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
816 NoSuchFieldException
817 {
818 Constructor<?> constructor = scalarClass.getConstructor(double.class, getUnitClass(scalarClass));
819 if (doubleType)
820 {
821 double zeroValue = 1.23456;
822 AbstractDoubleScalar<?,
823 ?> zero = abs
824 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(zeroValue,
825 getSIUnitInstance(getUnitClass(scalarClass), abs))
826 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(zeroValue,
827 getSIUnitInstance(getUnitClass(scalarClass), abs));
828 double oneValue = 3.45678;
829 AbstractDoubleScalar<?,
830 ?> one = abs
831 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(oneValue,
832 getSIUnitInstance(getUnitClass(scalarClass), abs))
833 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(oneValue,
834 getSIUnitInstance(getUnitClass(scalarClass), abs));
835 for (double ratio : new double[] { -5, -1, 0, 0.3, 1, 2, 10 })
836 {
837 double expectedResult = (1.0 - ratio) * zeroValue + ratio * oneValue;
838 Method interpolate =
839 ClassUtil.resolveMethod(scalarClass, "interpolate", scalarClass, scalarClass, double.class);
840 AbstractDoubleScalar<?, ?> result;
841 result = (AbstractDoubleScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
842 assertEquals("Result of operation", expectedResult, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
843 0.01);
844 }
845 }
846 else
847 {
848 float zeroValue = 1.23456f;
849 AbstractFloatScalar<?,
850 ?> zero = abs
851 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance(zeroValue,
852 getSIUnitInstance(getUnitClass(scalarClass), abs))
853 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance(zeroValue,
854 getSIUnitInstance(getUnitClass(scalarClass), abs));
855 float oneValue = 3.45678f;
856 AbstractFloatScalar<?,
857 ?> one = abs
858 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance(oneValue,
859 getSIUnitInstance(getUnitClass(scalarClass), abs))
860 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance(oneValue,
861 getSIUnitInstance(getUnitClass(scalarClass), abs));
862 for (float ratio : new float[] { -5, -1, 0, 0.3f, 1, 2, 10 })
863 {
864 float expectedResult = (1.0f - ratio) * zeroValue + ratio * oneValue;
865 Method interpolate = ClassUtil.resolveMethod(scalarClass, "interpolate", scalarClass, scalarClass, float.class);
866 AbstractFloatScalar<?, ?> result;
867 result = (AbstractFloatScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
868 assertEquals("Result of operation", expectedResult, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
869 0.01);
870 }
871 }
872 }
873
874 }