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