mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
Merge pull request #17 from icu-units/units_exportconverter
Export addSingleFactorConstant in header file
This commit is contained in:
commit
f357b5558e
2 changed files with 159 additions and 146 deletions
|
@ -18,133 +18,102 @@
|
|||
U_NAMESPACE_BEGIN
|
||||
namespace units {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Internal Structure */
|
||||
|
||||
enum Constants {
|
||||
CONSTANT_FT2M, // ft2m stands for foot to meter.
|
||||
CONSTANT_PI, // PI
|
||||
CONSTANT_GRAVITY, // Gravity
|
||||
CONSTANT_G,
|
||||
CONSTANT_GAL_IMP2M3, // Gallon imp to m3
|
||||
CONSTANT_LB2KG, // Pound to Kilogram
|
||||
|
||||
// Must be the last element.
|
||||
CONSTANTS_COUNT
|
||||
};
|
||||
|
||||
typedef enum SigNum {
|
||||
NEGATIVE = -1,
|
||||
POSITIVE = 1,
|
||||
} SigNum;
|
||||
|
||||
/* Represents a conversion factor */
|
||||
struct Factor {
|
||||
double factorNum = 1;
|
||||
double factorDen = 1;
|
||||
double offset = 0;
|
||||
bool reciprocal = false;
|
||||
int32_t constants[CONSTANTS_COUNT] = {};
|
||||
|
||||
void multiplyBy(const Factor &rhs) {
|
||||
factorNum *= rhs.factorNum;
|
||||
factorDen *= rhs.factorDen;
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] += rhs.constants[i];
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// We need the offset when the source and the target are simple units. e.g. the source is
|
||||
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
|
||||
offset = std::max(rhs.offset, offset);
|
||||
void Factor::multiplyBy(const Factor &rhs) {
|
||||
factorNum *= rhs.factorNum;
|
||||
factorDen *= rhs.factorDen;
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] += rhs.constants[i];
|
||||
}
|
||||
|
||||
void divideBy(const Factor &rhs) {
|
||||
factorNum *= rhs.factorDen;
|
||||
factorDen *= rhs.factorNum;
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] -= rhs.constants[i];
|
||||
}
|
||||
// NOTE
|
||||
// We need the offset when the source and the target are simple units. e.g. the source is
|
||||
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
|
||||
offset = std::max(rhs.offset, offset);
|
||||
}
|
||||
|
||||
// NOTE
|
||||
// We need the offset when the source and the target are simple units. e.g. the source is
|
||||
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
|
||||
offset = std::max(rhs.offset, offset);
|
||||
void Factor::divideBy(const Factor &rhs) {
|
||||
factorNum *= rhs.factorDen;
|
||||
factorDen *= rhs.factorNum;
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] -= rhs.constants[i];
|
||||
}
|
||||
|
||||
// Apply the power to the factor.
|
||||
void power(int32_t power) {
|
||||
// multiply all the constant by the power.
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] *= power;
|
||||
}
|
||||
// NOTE
|
||||
// We need the offset when the source and the target are simple units. e.g. the source is
|
||||
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
|
||||
offset = std::max(rhs.offset, offset);
|
||||
}
|
||||
|
||||
bool shouldFlip = power < 0; // This means that after applying the absolute power, we should flip
|
||||
// the Numerator and Denominator.
|
||||
|
||||
factorNum = std::pow(factorNum, std::abs(power));
|
||||
factorDen = std::pow(factorDen, std::abs(power));
|
||||
|
||||
if (shouldFlip) {
|
||||
// Flip Numerator and Denominator.
|
||||
std::swap(factorNum, factorDen);
|
||||
}
|
||||
void Factor::power(int32_t power) {
|
||||
// multiply all the constant by the power.
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] *= power;
|
||||
}
|
||||
|
||||
// Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2
|
||||
void flip() {
|
||||
bool shouldFlip = power < 0; // This means that after applying the absolute power, we should flip
|
||||
// the Numerator and Denominator.
|
||||
|
||||
factorNum = std::pow(factorNum, std::abs(power));
|
||||
factorDen = std::pow(factorDen, std::abs(power));
|
||||
|
||||
if (shouldFlip) {
|
||||
// Flip Numerator and Denominator.
|
||||
std::swap(factorNum, factorDen);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] *= -1;
|
||||
}
|
||||
void Factor::flip() {
|
||||
std::swap(factorNum, factorDen);
|
||||
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
constants[i] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Factor::applySiPrefix(UMeasureSIPrefix siPrefix) {
|
||||
if (siPrefix == UMeasureSIPrefix::UMEASURE_SI_PREFIX_ONE) return; // No need to do anything
|
||||
|
||||
double siApplied = std::pow(10.0, std::abs(siPrefix));
|
||||
|
||||
if (siPrefix < 0) {
|
||||
factorDen *= siApplied;
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply SI prefix to the `Factor`
|
||||
void applySiPrefix(UMeasureSIPrefix siPrefix) {
|
||||
if (siPrefix == UMeasureSIPrefix::UMEASURE_SI_PREFIX_ONE) return; // No need to do anything
|
||||
factorNum *= siApplied;
|
||||
}
|
||||
|
||||
double siApplied = std::pow(10.0, std::abs(siPrefix));
|
||||
void Factor::substituteConstants() {
|
||||
double constantsValues[CONSTANTS_COUNT];
|
||||
|
||||
if (siPrefix < 0) {
|
||||
factorDen *= siApplied;
|
||||
return;
|
||||
// TODO: Load those constant values from units data.
|
||||
constantsValues[CONSTANT_FT2M] = 0.3048;
|
||||
constantsValues[CONSTANT_PI] = 411557987.0 / 131002976.0;
|
||||
constantsValues[CONSTANT_GRAVITY] = 9.80665;
|
||||
constantsValues[CONSTANT_G] = 6.67408E-11;
|
||||
constantsValues[CONSTANT_LB2KG] = 0.45359237;
|
||||
constantsValues[CONSTANT_GAL_IMP2M3] = 0.00454609;
|
||||
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
if (this->constants[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
factorNum *= siApplied;
|
||||
}
|
||||
auto absPower = std::abs(this->constants[i]);
|
||||
SigNum powerSig = this->constants[i] < 0 ? SigNum::NEGATIVE : SigNum::POSITIVE;
|
||||
double absConstantValue = std::pow(constantsValues[i], absPower);
|
||||
|
||||
void substituteConstants() {
|
||||
double constantsValues[CONSTANTS_COUNT];
|
||||
|
||||
// TODO: Load those constant values from units data.
|
||||
constantsValues[CONSTANT_FT2M] = 0.3048;
|
||||
constantsValues[CONSTANT_PI] = 411557987.0 / 131002976.0;
|
||||
constantsValues[CONSTANT_GRAVITY] = 9.80665;
|
||||
constantsValues[CONSTANT_G] = 6.67408E-11;
|
||||
constantsValues[CONSTANT_LB2KG] = 0.45359237;
|
||||
constantsValues[CONSTANT_GAL_IMP2M3] = 0.00454609;
|
||||
|
||||
for (int i = 0; i < CONSTANTS_COUNT; i++) {
|
||||
if (this->constants[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto absPower = std::abs(this->constants[i]);
|
||||
SigNum powerSig = this->constants[i] < 0 ? SigNum::NEGATIVE : SigNum::POSITIVE;
|
||||
double absConstantValue = std::pow(constantsValues[i], absPower);
|
||||
|
||||
if (powerSig == SigNum::NEGATIVE) {
|
||||
this->factorDen *= absConstantValue;
|
||||
} else {
|
||||
this->factorNum *= absConstantValue;
|
||||
}
|
||||
|
||||
this->constants[i] = 0;
|
||||
if (powerSig == SigNum::NEGATIVE) {
|
||||
this->factorDen *= absConstantValue;
|
||||
} else {
|
||||
this->factorNum *= absConstantValue;
|
||||
}
|
||||
|
||||
this->constants[i] = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Helpers */
|
||||
|
||||
|
@ -184,44 +153,6 @@ double strHasDivideSignToDouble(StringPiece strWithDivide, UErrorCode &status) {
|
|||
return strToDouble(strWithDivide, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
|
||||
*/
|
||||
void addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum, Factor &factor,
|
||||
UErrorCode &status) {
|
||||
|
||||
if (baseStr == "ft_to_m") {
|
||||
factor.constants[CONSTANT_FT2M] += power * sigNum;
|
||||
} else if (baseStr == "ft2_to_m2") {
|
||||
factor.constants[CONSTANT_FT2M] += 2 * power * sigNum;
|
||||
} else if (baseStr == "ft3_to_m3") {
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
} else if (baseStr == "in3_to_m3") {
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
factor.factorDen *= 12 * 12 * 12;
|
||||
} else if (baseStr == "gal_to_m3") {
|
||||
factor.factorNum *= 231;
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
factor.factorDen *= 12 * 12 * 12;
|
||||
} else if (baseStr == "gal_imp_to_m3") {
|
||||
factor.constants[CONSTANT_GAL_IMP2M3] += power * sigNum;
|
||||
} else if (baseStr == "G") {
|
||||
factor.constants[CONSTANT_G] += power * sigNum;
|
||||
} else if (baseStr == "gravity") {
|
||||
factor.constants[CONSTANT_GRAVITY] += power * sigNum;
|
||||
} else if (baseStr == "lb_to_kg") {
|
||||
factor.constants[CONSTANT_LB2KG] += power * sigNum;
|
||||
} else if (baseStr == "PI") {
|
||||
factor.constants[CONSTANT_PI] += power * sigNum;
|
||||
} else {
|
||||
if (sigNum == SigNum::NEGATIVE) {
|
||||
factor.factorDen *= std::pow(strToDouble(baseStr, status), power);
|
||||
} else {
|
||||
factor.factorNum *= std::pow(strToDouble(baseStr, status), power);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Adds single factor to a `Factor` object. Single factor means "23^2", "23.3333", "ft2m^3" ...etc.
|
||||
However, complex factor are not included, such as "ft2m^3*200/3"
|
||||
|
@ -387,6 +318,41 @@ void loadConversionRate(ConversionRate &conversionRate, const MeasureUnit &sourc
|
|||
|
||||
} // namespace
|
||||
|
||||
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum,
|
||||
Factor &factor, UErrorCode &status) {
|
||||
|
||||
if (baseStr == "ft_to_m") {
|
||||
factor.constants[CONSTANT_FT2M] += power * sigNum;
|
||||
} else if (baseStr == "ft2_to_m2") {
|
||||
factor.constants[CONSTANT_FT2M] += 2 * power * sigNum;
|
||||
} else if (baseStr == "ft3_to_m3") {
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
} else if (baseStr == "in3_to_m3") {
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
factor.factorDen *= 12 * 12 * 12;
|
||||
} else if (baseStr == "gal_to_m3") {
|
||||
factor.factorNum *= 231;
|
||||
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
|
||||
factor.factorDen *= 12 * 12 * 12;
|
||||
} else if (baseStr == "gal_imp_to_m3") {
|
||||
factor.constants[CONSTANT_GAL_IMP2M3] += power * sigNum;
|
||||
} else if (baseStr == "G") {
|
||||
factor.constants[CONSTANT_G] += power * sigNum;
|
||||
} else if (baseStr == "gravity") {
|
||||
factor.constants[CONSTANT_GRAVITY] += power * sigNum;
|
||||
} else if (baseStr == "lb_to_kg") {
|
||||
factor.constants[CONSTANT_LB2KG] += power * sigNum;
|
||||
} else if (baseStr == "PI") {
|
||||
factor.constants[CONSTANT_PI] += power * sigNum;
|
||||
} else {
|
||||
if (sigNum == SigNum::NEGATIVE) {
|
||||
factor.factorDen *= std::pow(strToDouble(baseStr, status), power);
|
||||
} else {
|
||||
factor.factorNum *= std::pow(strToDouble(baseStr, status), power);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the compound base unit of a compound unit (`source`). For example, if the source unit is
|
||||
* `square-mile-per-hour`, the compound base unit will be `square-meter-per-second`
|
||||
|
|
|
@ -16,6 +16,53 @@
|
|||
U_NAMESPACE_BEGIN
|
||||
namespace units {
|
||||
|
||||
/* Internal Structure */
|
||||
|
||||
enum Constants {
|
||||
CONSTANT_FT2M, // ft2m stands for foot to meter.
|
||||
CONSTANT_PI, // PI
|
||||
CONSTANT_GRAVITY, // Gravity
|
||||
CONSTANT_G,
|
||||
CONSTANT_GAL_IMP2M3, // Gallon imp to m3
|
||||
CONSTANT_LB2KG, // Pound to Kilogram
|
||||
|
||||
// Must be the last element.
|
||||
CONSTANTS_COUNT
|
||||
};
|
||||
|
||||
typedef enum SigNum {
|
||||
NEGATIVE = -1,
|
||||
POSITIVE = 1,
|
||||
} SigNum;
|
||||
|
||||
/* Represents a conversion factor */
|
||||
struct Factor {
|
||||
double factorNum = 1;
|
||||
double factorDen = 1;
|
||||
double offset = 0;
|
||||
bool reciprocal = false;
|
||||
int32_t constants[CONSTANTS_COUNT] = {};
|
||||
|
||||
void multiplyBy(const Factor &rhs);
|
||||
void divideBy(const Factor &rhs);
|
||||
|
||||
// Apply the power to the factor.
|
||||
void power(int32_t power);
|
||||
|
||||
// Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2
|
||||
void flip();
|
||||
|
||||
// Apply SI prefix to the `Factor`
|
||||
void applySiPrefix(UMeasureSIPrefix siPrefix);
|
||||
void substituteConstants();
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
|
||||
*/
|
||||
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum,
|
||||
Factor &factor, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Represents the conversion rate between `source` and `target`.
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue