com.swirlds.common.units.internal.UnitConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.swirlds.common.units.internal;
import com.swirlds.common.units.Unit;
/**
* Boilerplate code for converting between units of the same type.
*
* @param the type of the unit
*/
public class UnitConverter> {
/**
* Describes a unit with respect to the previous unit in the unit sequence.
*
* @param type the type identifier for this unit
* @param factor the number which the previous unit must be multiplied by in order to reach this unit
* @param the unit family type for this unit
*/
public record UnitConversion(T type, long factor) {}
/**
* An in-order sequence of units.
*/
private final T[] types;
/**
* Factors for converting between units.
*/
private final long[] factors;
/**
* Create a new unit converter.
*
* @param units an in-order array of units
*/
@SuppressWarnings("unchecked")
public UnitConverter(final T... units) {
factors = new long[units.length * units.length];
types = (T[]) new Unit[units.length];
for (final T from : units) {
types[from.ordinal()] = from;
for (final T to : units) {
int index = getConversionFactorIndex(from, to);
factors[index] = 1;
if (from.ordinal() > to.ordinal()) {
for (int i = from.ordinal(); i > to.ordinal(); i--) {
factors[index] *= units[i].getConversionFactor();
}
} else {
for (int i = to.ordinal(); i > from.ordinal(); i--) {
factors[index] *= units[i].getConversionFactor();
}
}
}
}
}
/**
* Get the index in {@link #factors} for a particular conversion pair.
*
* @param to the starting unit
* @param from the resulting unit
* @return the factor that should be multiplied or divided for the conversion
*/
private int getConversionFactorIndex(final Unit to, final Unit from) {
return to.ordinal() * types.length + from.ordinal();
}
/**
* Simplify a quantity to the best unit.
*
* @param quantity the quantity
* @param unit the original unit
* @return the new unit
*/
public Unit.SimplifiedQuantity simplify(final double quantity, final T unit) {
double currentQuantity = quantity;
int currentIndex = unit.ordinal();
while (currentIndex > 0 && Math.abs(currentQuantity) < 1.0) {
currentIndex--;
currentQuantity = convertTo(quantity, unit, types[currentIndex]);
}
while (currentIndex < types.length - 1
&& Math.abs(currentQuantity) >= types[currentIndex + 1].getConversionFactor()) {
currentIndex++;
currentQuantity = convertTo(quantity, unit, types[currentIndex]);
}
return new Unit.SimplifiedQuantity<>(currentQuantity, types[currentIndex]);
}
/**
* Convert from one unit to another.
*
* @param quantity the original quantity
* @param from the original unit
* @param to the new unit
* @return the new quantity
*/
public double convertTo(final double quantity, final T from, final T to) {
if (from == to) {
return quantity;
}
final long factor = factors[getConversionFactorIndex(from, to)];
if (from.ordinal() > to.ordinal()) {
return quantity * factor;
} else {
return quantity / factor;
}
}
/**
* Convert from one unit to another.
*
* @param quantity the original quantity
* @param from the original unit
* @param to the new unit
* @return the new quantity
*/
public double convertTo(final long quantity, final T from, final T to) {
if (from == to) {
return quantity;
}
final long factor = factors[getConversionFactorIndex(from, to)];
if (from.ordinal() > to.ordinal()) {
return (double) (quantity * factor);
} else {
return ((double) quantity) / factor;
}
}
}