View Javadoc
1   package org.djunits.value.vfloat.scalar.base;
2   
3   import java.lang.reflect.Constructor;
4   import java.lang.reflect.InvocationTargetException;
5   import java.util.HashMap;
6   import java.util.Map;
7   
8   import org.djunits.unit.AbsoluteLinearUnit;
9   import org.djunits.unit.SIUnit;
10  import org.djunits.unit.Unit;
11  import org.djunits.unit.si.SIPrefixes;
12  import org.djunits.unit.util.UnitRuntimeException;
13  import org.djunits.value.Absolute;
14  import org.djunits.value.base.Scalar;
15  import org.djunits.value.formatter.Format;
16  import org.djunits.value.util.ValueUtil;
17  import org.djunits.value.vfloat.scalar.FloatSIScalar;
18  
19  /**
20   * Static methods to create and operate on FloatScalars.
21   * <p>
22   * Copyright (c) 2015-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
23   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
24   * </p>
25   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
26   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
27   * @param <U> the unit
28   * @param <S> the type
29   */
30  public abstract class FloatScalar<U extends Unit<U>, S extends FloatScalar<U, S>> extends Scalar<U, S>
31  {
32      /** */
33      private static final long serialVersionUID = 20161015L;
34  
35      /** The value, stored in the standard SI unit. */
36      @SuppressWarnings("checkstyle:visibilitymodifier")
37      public final float si;
38  
39      /**
40       * Construct a new FFloatScalar
41       * @param unit U; the unit
42       * @param si float; the si value to store
43       */
44      public FloatScalar(final U unit, final float si)
45      {
46          super(unit);
47          this.si = si;
48      }
49  
50      /**
51       * Return the value in the underlying SI unit.
52       * @return float; the value in the underlying SI unit
53       */
54      public final float getSI()
55      {
56          return this.si;
57      }
58  
59      /**
60       * Retrieve the value in the original unit.
61       * @return float
62       */
63      public final float getInUnit()
64      {
65          return (float) ValueUtil.expressAsUnit(getSI(), getDisplayUnit());
66      }
67  
68      /**
69       * Retrieve the value converted into some specified unit.
70       * @param targetUnit U; the unit to convert the value into
71       * @return float
72       */
73      public final float getInUnit(final U targetUnit)
74      {
75          return (float) ValueUtil.expressAsUnit(getSI(), targetUnit);
76      }
77  
78      /** {@inheritDoc} */
79      @Override
80      public final boolean lt(final S o)
81      {
82          return this.getSI() < o.getSI();
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public final boolean le(final S o)
88      {
89          return this.getSI() <= o.getSI();
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public final boolean gt(final S o)
95      {
96          return this.getSI() > o.getSI();
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public final boolean ge(final S o)
102     {
103         return this.getSI() >= o.getSI();
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public final boolean eq(final S o)
109     {
110         return this.getSI() == o.getSI();
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public final boolean ne(final S o)
116     {
117         return this.getSI() != o.getSI();
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     public final boolean lt0()
123     {
124         return this.getSI() < 0.0;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public final boolean le0()
130     {
131         return this.getSI() <= 0.0;
132     }
133 
134     /** {@inheritDoc} */
135     @Override
136     public final boolean gt0()
137     {
138         return this.getSI() > 0.0;
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public final boolean ge0()
144     {
145         return this.getSI() >= 0.0;
146     }
147 
148     /** {@inheritDoc} */
149     @Override
150     public final boolean eq0()
151     {
152         return this.getSI() == 0.0;
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public final boolean ne0()
158     {
159         return this.getSI() != 0.0;
160     }
161 
162     /** {@inheritDoc} */
163     @Override
164     public final int compareTo(final S o)
165     {
166         return Float.compare(this.getSI(), o.getSI());
167     }
168 
169     /** {@inheritDoc} */
170     @Override
171     public int intValue()
172     {
173         return (int) this.getSI();
174     }
175 
176     /** {@inheritDoc} */
177     @Override
178     public long longValue()
179     {
180         return (long) this.getSI();
181     }
182 
183     /** {@inheritDoc} */
184     @Override
185     public float floatValue()
186     {
187         return this.getSI();
188     }
189 
190     /** {@inheritDoc} */
191     @Override
192     public double doubleValue()
193     {
194         return this.getSI();
195     }
196 
197     /**********************************************************************************/
198     /********************************* GENERIC METHODS ********************************/
199     /**********************************************************************************/
200 
201     /** {@inheritDoc} */
202     @Override
203     public String toString()
204     {
205         return toString(getDisplayUnit(), false, true);
206     }
207 
208     /** {@inheritDoc} */
209     @Override
210     public String toString(final U displayUnit)
211     {
212         return toString(displayUnit, false, true);
213     }
214 
215     /** {@inheritDoc} */
216     @Override
217     public String toString(final boolean verbose, final boolean withUnit)
218     {
219         return toString(getDisplayUnit(), verbose, withUnit);
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     public String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
225     {
226         StringBuffer buf = new StringBuffer();
227         if (verbose)
228         {
229             buf.append(this instanceof Absolute ? "Abs " : "Rel ");
230         }
231         float d = (float) ValueUtil.expressAsUnit(getSI(), displayUnit);
232         buf.append(Format.format(d));
233         if (withUnit)
234         {
235             buf.append(" "); // Insert one space as prescribed by SI writing conventions
236             buf.append(displayUnit.getLocalizedDisplayAbbreviation());
237         }
238         return buf.toString();
239     }
240 
241     /**
242      * Format this DoubleScalar in SI unit using prefixes when possible. If the value is too small or too large,
243      * e-notation and the plain SI unit are used.
244      * @return String; formatted value of this DoubleScalar
245      */
246     public String toStringSIPrefixed()
247     {
248         return toStringSIPrefixed(-24, 26);
249     }
250 
251     /**
252      * Format this DoubleScalar in SI unit using prefixes when possible and within the specified size range. If the
253      * value is too small or too large, e-notation and the plain SI unit are used.
254      * @param smallestPower int; the smallest exponent value that will be written using an SI prefix
255      * @param biggestPower int; the largest exponent value that will be written using an SI prefix
256      * @return String; formatted value of this DoubleScalar
257      */
258     public String toStringSIPrefixed(final int smallestPower, final int biggestPower)
259     {
260         // Override this method for weights, nonlinear units and DimensionLess.
261         if (!Double.isFinite(this.si))
262         {
263             return toString(getDisplayUnit().getStandardUnit());
264         }
265         // PK: I can't think of an easier way to figure out what the exponent will be; rounding of the mantissa to the available
266         // width makes this hard; This feels like an expensive way.
267         String check = String.format(this.si >= 0 ? "%10.8E" : "%10.7E", this.si);
268         int exponent = Integer.parseInt(check.substring(check.indexOf("E") + 1));
269         if (exponent < -24 || exponent < smallestPower || exponent > 24 + 2 || exponent > biggestPower)
270         {
271             // Out of SI prefix range; do not scale.
272             return String.format(this.si >= 0 ? "%10.4E" : "%10.3E", this.si) + " "
273                     + getDisplayUnit().getStandardUnit().getId();
274         }
275         Integer roundedExponent = (int) Math.ceil((exponent - 2.0) / 3) * 3;
276         // System.out.print(String.format("exponent=%d; roundedExponent=%d ", exponent, roundedExponent));
277         String key =
278                 SIPrefixes.FACTORS.get(roundedExponent).getDefaultTextualPrefix() + getDisplayUnit().getStandardUnit().getId();
279         U displayUnit = getDisplayUnit().getQuantity().getUnitByAbbreviation(key);
280         return toString(displayUnit);
281     }
282 
283     /** {@inheritDoc} */
284     @Override
285     public String toTextualString()
286     {
287         return toTextualString(getDisplayUnit());
288     }
289 
290     /** {@inheritDoc} */
291     @Override
292     public String toTextualString(final U displayUnit)
293     {
294         float f = (float) ValueUtil.expressAsUnit(getSI(), displayUnit);
295         return format(f) + " " + displayUnit.getLocalizedTextualAbbreviation();
296     }
297 
298     /** {@inheritDoc} */
299     @Override
300     public String toDisplayString()
301     {
302         return toDisplayString(getDisplayUnit());
303     }
304 
305     /** {@inheritDoc} */
306     @Override
307     public String toDisplayString(final U displayUnit)
308     {
309         float f = (float) ValueUtil.expressAsUnit(getSI(), displayUnit);
310         return format(f) + " " + displayUnit.getLocalizedDisplayAbbreviation();
311     }
312 
313     /** {@inheritDoc} */
314     @Override
315     @SuppressWarnings("checkstyle:designforextension")
316     public int hashCode()
317     {
318         final int prime = 31;
319         int result = getDisplayUnit().getStandardUnit().hashCode();
320         long temp;
321         temp = Float.floatToIntBits(this.getSI());
322         result = prime * result + (int) (temp ^ (temp >>> 32));
323         return result;
324     }
325 
326     /** {@inheritDoc} */
327     @Override
328     @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces", "unchecked"})
329     public boolean equals(final Object obj)
330     {
331         if (this == obj)
332             return true;
333         if (obj == null)
334             return false;
335         if (getClass() != obj.getClass())
336             return false;
337         FloatScalar<U, S> other = (FloatScalar<U, S>) obj;
338         if (!getDisplayUnit().getStandardUnit().equals(other.getDisplayUnit().getStandardUnit()))
339             return false;
340         if (Float.floatToIntBits(this.getSI()) != Float.floatToIntBits(other.getSI()))
341             return false;
342         return true;
343     }
344 
345     /**********************************************************************************/
346     /********************************* STATIC METHODS *********************************/
347     /**********************************************************************************/
348 
349     /** The cache to make the lookup of the constructor for a Scalar belonging to a unit faster. */
350     private static final Map<Unit<?>, Constructor<? extends FloatScalar<?, ?>>> CACHE = new HashMap<>();
351 
352     /**
353      * Instantiate the FloatScalar based on its unit. Rigid check on types by the compiler.
354      * @param value float; the value
355      * @param unit U; the unit in which the value is expressed
356      * @return S; an instantiated FloatScalar with the value expressed in the unit
357      * @param <U> the unit
358      * @param <S> the return type
359      */
360     public static <U extends Unit<U>, S extends FloatScalar<U, S>> S instantiate(final float value, final U unit)
361     {
362         return instantiateAnonymous(value, unit);
363     }
364 
365     /**
366      * Instantiate the FloatScalar with an SI value and add the displayUnit later. Rigid check on types by the compiler.
367      * @param valueSI float; the SIvalue
368      * @param displayUnit U; the unit in which the value will be displayed
369      * @return S; an instantiated FloatScalar with the SI value and the display unit
370      * @param <U> the unit
371      * @param <S> the return type
372      */
373     public static <U extends Unit<U>, S extends FloatScalar<U, S>> S instantiateSI(final float valueSI, final U displayUnit)
374     {
375         S result = instantiateAnonymous(valueSI, displayUnit.getStandardUnit());
376         result.setDisplayUnit(displayUnit);
377         return result;
378     }
379 
380     /**
381      * Instantiate the FloatScalar based on its unit. Loose check for types on the compiler. This allows the unit to be
382      * specified as a Unit&lt;?&gt; type.<br>
383      * <b>Note</b> that it is possible to make mistakes with anonymous units.
384      * @param value float; the value
385      * @param unit Unit&lt;?&gt;; the unit in which the value is expressed
386      * @return S; an instantiated FloatScalar with the value expressed in the unit
387      * @param <S> the return type
388      */
389     @SuppressWarnings("unchecked")
390     public static <S extends FloatScalar<?, S>> S instantiateAnonymous(final float value, final Unit<?> unit)
391     {
392         try
393         {
394             Constructor<? extends FloatScalar<?, ?>> scalarConstructor = CACHE.get(unit);
395             if (scalarConstructor == null)
396             {
397                 if (!unit.getClass().getSimpleName().endsWith("Unit"))
398                 {
399                     throw new ClassNotFoundException("Unit " + unit.getClass().getSimpleName()
400                             + " name does noet end with 'Unit'. Cannot find corresponding scalar");
401                 }
402                 Class<? extends FloatScalar<?, ?>> scalarClass;
403                 if (unit instanceof SIUnit)
404                 {
405                     scalarClass = FloatSIScalar.class;
406                 }
407                 else
408                 {
409                     scalarClass = (Class<FloatScalar<?, ?>>) Class.forName(
410                             "org.djunits.value.vfloat.scalar.Float" + unit.getClass().getSimpleName().replace("Unit", ""));
411                 }
412                 scalarConstructor = scalarClass.getDeclaredConstructor(float.class, unit.getClass());
413                 CACHE.put(unit, scalarConstructor);
414             }
415             return (S) scalarConstructor.newInstance(value, unit);
416         }
417         catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
418                 | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception)
419         {
420             throw new UnitRuntimeException(
421                     "Cannot instantiate FloatScalar of unit " + unit.toString() + ". Reason: " + exception.getMessage());
422         }
423     }
424 
425     /**
426      * Add a Relative value to an Absolute value. Return a new instance of the value. The unit of the return value will be the
427      * unit of the left argument.
428      * @param left A, an absolute typed FloatScalar; the left argument
429      * @param right R, a relative typed FloatScalar; the right argument
430      * @param <AU> Unit; the absolute unit of the parameters and the result
431      * @param <RU> Unit; the relative unit of the parameters and the result
432      * @param <R> the relative type
433      * @param <A> the corresponding absolute type
434      * @return A; an absolute typed FloatScalar; the sum of the values as an Absolute value
435      */
436     public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
437             R extends FloatScalarRelWithAbs<AU, A, RU, R>,
438             A extends FloatScalarAbs<AU, A, RU, R>> A plus(final A left, final R right)
439     {
440         return left.plus(right);
441     }
442 
443     /**
444      * Add an Absolute value to a Relative value. Return a new instance of the value. The unit of the return value will be the
445      * unit of the left argument.
446      * @param left A, an absolute typed FloatScalar; the left argument
447      * @param right R, a relative typed FloatScalar; the right argument
448      * @param <AU> Unit; the absolute unit of the parameters and the result
449      * @param <RU> Unit; the relative unit of the parameters and the result
450      * @param <R> the relative type
451      * @param <A> the corresponding absolute type
452      * @return A; an absolute typed FloatScalar; the sum of the values as an Absolute value
453      */
454     public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
455             R extends FloatScalarRelWithAbs<AU, A, RU, R>,
456             A extends FloatScalarAbs<AU, A, RU, R>> A plus(final R left, final A right)
457     {
458         return right.plus(left);
459     }
460 
461     /**
462      * Add a Relative value to a Relative value. Return a new instance of the value. The unit of the return value will be the
463      * unit of the left argument.
464      * @param left R, a relative typed FloatScalar; the left argument
465      * @param right R, a relative typed FloatScalar; the right argument
466      * @param <U> Unit; the unit of the parameters and the result
467      * @param <R> the relative type
468      * @return R; a relative typed FloatScalar; the sum of the values as a Relative value
469      */
470     public static <U extends Unit<U>, R extends FloatScalarRel<U, R>> R plus(final R left, final R right)
471     {
472         return left.plus(right);
473     }
474 
475     /**
476      * Subtract a Relative value from an absolute value. Return a new instance of the value. The unit of the return value will
477      * be the unit of the left argument.
478      * @param left A, an absolute typed FloatScalar; the left value
479      * @param right R, a relative typed FloatScalar; the right value
480      * @param <AU> Unit; the absolute unit of the parameters and the result
481      * @param <RU> Unit; the relative unit of the parameters and the result
482      * @param <R> the relative type
483      * @param <A> the corresponding absolute type
484      * @return A; an absolute typed FloatScalar; the resulting value as an absolute value
485      */
486     public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
487             R extends FloatScalarRelWithAbs<AU, A, RU, R>,
488             A extends FloatScalarAbs<AU, A, RU, R>> A minus(final A left, final R right)
489     {
490         return left.minus(right);
491     }
492 
493     /**
494      * Subtract a relative value from a relative value. Return a new instance of the value. The unit of the value will be the
495      * unit of the first argument.
496      * @param left R, a relative typed FloatScalar; the left value
497      * @param right R, a relative typed FloatScalar; the right value
498      * @param <U> Unit; the unit of the parameters and the result
499      * @param <R> the relative type
500      * @return R; a relative typed FloatScalar; the resulting value as a relative value
501      */
502     public static <U extends Unit<U>, R extends FloatScalarRel<U, R>> R minus(final R left, final R right)
503     {
504         return left.minus(right);
505     }
506 
507     /**
508      * Subtract two absolute values. Return a new instance of a relative value of the difference. The unit of the value will be
509      * the unit of the first argument.
510      * @param left A, an absolute typed FloatScalar; value 1
511      * @param right A, an absolute typed FloatScalar; value 2
512      * @param <AU> Unit; the absolute unit of the parameters and the result
513      * @param <RU> Unit; the relative unit of the parameters and the result
514      * @param <R> the relative type
515      * @param <A> the corresponding absolute type
516      * @return R; a relative typed FloatScalar; the difference of the two absolute values as a relative value
517      */
518     public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
519             R extends FloatScalarRelWithAbs<AU, A, RU, R>,
520             A extends FloatScalarAbs<AU, A, RU, R>> R minus(final A left, final A right)
521     {
522         return left.minus(right);
523     }
524 
525     /**
526      * Multiply two values; the result is a new instance with a different (existing or generated) SI unit.
527      * @param left FloatScalarRel&lt;?, ?&gt;; the left operand
528      * @param right FloatScalarRel&lt;?, ?&gt;; the right operand
529      * @return FloatScalarRel&lt;SIUnit&gt;; the product of the two values
530      */
531     public static FloatSIScalar multiply(final FloatScalarRel<?, ?> left, final FloatScalarRel<?, ?> right)
532     {
533         SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions()
534                 .plus(right.getDisplayUnit().getQuantity().getSiDimensions()));
535         return new FloatSIScalar(left.getSI() * right.getSI(), targetUnit);
536     }
537 
538     /**
539      * Divide two values; the result is a new instance with a different (existing or generated) SI unit.
540      * @param left FloatScalarRel&lt;?, ?&gt;; the left operand
541      * @param right FloatScalarRel&lt;?, ?&gt;; the right operand
542      * @return FloatScalarRel&lt;SIUnit&gt;; the ratio of the two values
543      */
544     public static FloatSIScalar divide(final FloatScalarRel<?, ?> left, final FloatScalarRel<?, ?> right)
545     {
546         SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions()
547                 .minus(right.getDisplayUnit().getQuantity().getSiDimensions()));
548         return new FloatSIScalar(left.getSI() / right.getSI(), targetUnit);
549     }
550 
551     /**
552      * Interpolate between two values. Made to be able to call e.g., Area a = FloatScalarinterpolate(a1, a2, 0.4);
553      * @param zero R; the low value
554      * @param one R; the high value
555      * @param ratio float; the ratio between 0 and 1, inclusive
556      * @param <U> Unit; the unit of the parameters and the result
557      * @param <R> the relative type
558      * @return R; an Absolute Scalar at the <code>ratio</code> between <code>zero</code> and <code>one</code>
559      */
560     public static <U extends Unit<U>, R extends FloatScalarRel<U, R>> R interpolate(final R zero, final R one,
561             final float ratio)
562     {
563         return zero.instantiateRel(zero.getInUnit() * (1 - ratio) + one.getInUnit(zero.getDisplayUnit()) * ratio,
564                 zero.getDisplayUnit());
565     }
566 
567     /**
568      * Interpolate between two values. Made to be able to call e.g., Time t = FloatScalarinterpolate(t1, t2, 0.4);
569      * @param zero A; the low value
570      * @param one A; the high value
571      * @param ratio float; the ratio between 0 and 1, inclusive
572      * @param <AU> Unit; the absolute unit of the parameters and the result
573      * @param <RU> Unit; the relative unit of the parameters and the result
574      * @param <R> the relative type
575      * @param <A> the corresponding absolute type
576      * @return R; a Relative Scalar at the <code>ratio</code> between <code>zero</code> and <code>one</code>
577      */
578     public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
579             R extends FloatScalarRelWithAbs<AU, A, RU, R>,
580             A extends FloatScalarAbs<AU, A, RU, R>> A interpolate(final A zero, final A one, final float ratio)
581     {
582         return zero.instantiateAbs(zero.getInUnit() * (1 - ratio) + one.getInUnit(zero.getDisplayUnit()) * ratio,
583                 zero.getDisplayUnit());
584     }
585 
586     /**
587      * Return the maximum value of two relative scalars.
588      * @param r1 T; the first scalar
589      * @param r2 T; the second scalar
590      * @param <U> Unit; the unit of the parameters and the result
591      * @param <T> the argument and result type
592      * @return T; the maximum value of two relative scalars
593      */
594     public static <U extends Unit<U>, T extends FloatScalar<U, T>> T max(final T r1, final T r2)
595     {
596         return (r1.gt(r2)) ? r1 : r2;
597     }
598 
599     /**
600      * Return the maximum value of more than two relative scalars.
601      * @param r1 T; the first scalar
602      * @param r2 T; the second scalar
603      * @param rn T...; the other scalars
604      * @param <U> Unit; the unit of the parameters and the result
605      * @param <T> the argument and result type
606      * @return T; the maximum value of more than two relative scalars
607      */
608     @SafeVarargs
609     public static <U extends Unit<U>, T extends FloatScalar<U, T>> T max(final T r1, final T r2, final T... rn)
610     {
611         T maxr = (r1.gt(r2)) ? r1 : r2;
612         for (T r : rn)
613         {
614             if (r.gt(maxr))
615             {
616                 maxr = r;
617             }
618         }
619         return maxr;
620     }
621 
622     /**
623      * Return the minimum value of two relative scalars.
624      * @param r1 T; the first scalar
625      * @param r2 T; the second scalar
626      * @param <U> Unit; the unit of the parameters and the result
627      * @param <T> the argument and result type
628      * @return T; the minimum value of two relative scalars
629      */
630     public static <U extends Unit<U>, T extends FloatScalar<U, T>> T min(final T r1, final T r2)
631     {
632         return r1.lt(r2) ? r1 : r2;
633     }
634 
635     /**
636      * Return the minimum value of more than two relative scalars.
637      * @param r1 T; the first scalar
638      * @param r2 T; the second scalar
639      * @param rn T...; the other scalars
640      * @param <U> Unit; the unit of the parameters and the result
641      * @param <T> the argument and result type
642      * @return T; the minimum value of more than two relative scalars
643      */
644     @SafeVarargs
645     public static <U extends Unit<U>, T extends FloatScalar<U, T>> T min(final T r1, final T r2, final T... rn)
646     {
647         T minr = r1.lt(r2) ? r1 : r2;
648         for (T r : rn)
649         {
650             if (r.lt(minr))
651             {
652                 minr = r;
653             }
654         }
655         return minr;
656     }
657 
658 }