Skip to content

Commit

Permalink
Remove measurement type (#6)
Browse files Browse the repository at this point in the history
* remove the measurement type and fixed_measurement_type templates and just use a concrete class

* fix a constexpr label on an expression and update the readme.

* fix a failing test on some systems for double comparison and a few warning fixes
  • Loading branch information
phlptp authored Dec 25, 2019
1 parent 90c9025 commit 38ddc19
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 167 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ There are only a few types in the library
- `detail::unit_base` is the base representation of physical units and powers. It uses a bitfield to store the base unit representation in a 4 byte representation. It is mostly expected that unit_base will not be used in a standalone context but through one of other types.
- `unit` is the primary type representing a physical unit it consists of a `float` multiplier along with a `unit_base` and contains this within an 8 byte type. The float has an accuracy of around 6 decimal digits. Units within that tolerance will compare equal.
- `precise_unit` is the a more accurate type representing a physical unit it consists of a `double` multiplier along with a `unit_base` and contains this within an 16 byte type. The double has an accuracy of around 13 decimal digits. Units within that tolerance will compare equal. The remaining 4 bytes are used to contain a commodity object code.
- `measurement` is a 16 byte type containing a double value along with a `unit` and mathematical operations can be performed on it usually producing a new measurement. `measurement` is an alias to a `measurement_base<double>` so the quantity type can be templated. `measurement_f` is an alias for `measurement_base<float>` but others could be defined.
- `measurement` is a 16 byte type containing a double value along with a `unit` and mathematical operations can be performed on it usually producing a new measurement.
- `precise_measurement` is similar to measurement except using a double for the quantity and a `precise_unit` as the units.
- `fixed_measurement` is a 16 byte type containing a double value along with a constant `unit` and mathematical operations can be performed on it usually producing a new `measurement`. `fixed_measurement` is an alias to a `fixed_measurement_base<double>` so the quantity type can be templated. `fixed_measurement_f` is an alias for `fixed_measurement_base<float>` but others could be defined. The distinction between `fixed_measurement` and `measurement` is that the unit definition of `fixed_measurement` is constant and any assignments get automatically converted, `fixed_measurement`'s are implicitly convertible to a `measurement` of the same value type. fixed_measurement also support some operation with pure numbers by assuming a unit that are not allowed on regular measurement types.
- `fixed_precise_measurement` is similar to `fixed_measurement` except it uses `precise_unit` as a base and uses a double for the measurement instead of a template.
- `fixed_measurement` is a 16 byte type containing a double value along with a constant `unit` and mathematical operations can be performed on it usually producing a new `measurement`. The distinction between `fixed_measurement` and `measurement` is that the unit definition of `fixed_measurement` is constant and any assignments get automatically converted, `fixed_measurement`'s are implicitly convertible to a `measurement` of the same value type. fixed_measurement also support some operation with pure numbers by assuming a unit that are not allowed on regular measurement types.
- `fixed_precise_measurement` is similar to `fixed_measurement` except it uses `precise_unit` as a base and uses a double for the measurement instead of a template, except it is 24 bytes instead of 16.

## Unit representation
The unit class consists of a multiplier and a representation of base units.
Expand Down Expand Up @@ -178,7 +178,7 @@ For precise_units only
- `<unit>=<unit>*<unit>` generate a new unit with the units multiplied ie `m*m` does what you might expect and produces a new unit with `m^2`
- `<unit>=<unit>/<unit>` generate a new unit with the units divided ie `m/s` does what you might expect and produces a new unit with meters per second. NOTE: `m/m` will produce `1` it will not automatically produce a `pu` though we are looking at how to make a 'pu_m*m=m' so units like strain might work smoothly.

- `bool <unit>==<unit>` compare two units. this does a rounding compare so there is some tolerance to roughly 7 significant digits for <unit> and 13 significant digits for <precise_unit>.
- `bool <unit>==<unit>` compare two units. this does a rounding compare so there is some tolerance to roughly 7 significant digits for \<unit> and 13 significant digits for <precise_unit>.
- `bool <unit>!=<unit>` the opposite of `==`

precise_units can usually operate with a precise unit or unit, unit usually can't operate on precise_unit.
Expand Down Expand Up @@ -211,13 +211,13 @@ These functions are not class methods but operate on units
- `<measurement> convert_to_base() const` convert to a base unit, i.e. a unit whose multiplier is 1.0.
- `<unit> units() const` get the units used as a basis for the measurement
- `<unit> as_unit() const` take the measurement as is and convert it into a single unit. For Examples say a was 10 m. calling as_unit() on that measurement would produce a unit with a multiplier of 10 and a base of meters.
- `double value_as(<unit>)` get the value of a measurement as if it were measured in <unit>
- `double value_as(<unit>)` get the value of a measurement as if it were measured in \<unit>

#### Measurement operators
There are several operator overloads which work on measurements or units to produce measurements.
- `'*', '/', '+','-'` are all defined for mathematical operations on a measurement and produce another measurement.
- `%` `*`, and `/` are defined for <measurement><op><double>
- `*`, and `/` are defined for <double><op><measurement>
- `%` `*`, and `/` are defined for \<measurement>\<op>\<double>
- `*`, and `/` are defined for \<double>\<op>\<measurement>

Notes: for regular measurements, `+` and `-` are not defined for doubles due to uncertainty of what that means. For fixed_measurement types this is defined as the units are known at construction and cannot change. For fixed_measurement types if the operator would produce a new measurement with the same units it will be a fixed measurement, if not it reverts to a regular measurement.

Expand All @@ -242,7 +242,7 @@ Notes: for regular measurements, `+` and `-` are not defined for doubles due to
- `std::string to_string([unit|measurement],flags)` : convert a unit or measurement to a string, all defined units or measurements listed above are supported
- `addUserDefinedUnit(std::string name, precise_unit un)` add a new unit that can be used in the string operations.
- `clearUserDefinedUnits()` remove all user defined units from the library.
- `disableUserDefinedUnits()` there is a performance hit if custom units are used so they can be disabled completely if desired.
- `disableUserDefinedUnits()` there is a(likely small-an additional unordered map lookup) performance hit in the string conversions functions if custom units are used so they can be disabled completely if desired.
- `enableUserDefinedUnits()` enable the use of UserDefinedUnits. they are enabled by default.

#### Commodities
Expand All @@ -251,7 +251,7 @@ The units library has some support for commodities, more might be added in the
- `std::string getCommodityName(uint32_t)` get the name of a commodity from its code
- `addUserDefinedCommodity(std::string name, uint32_t code)` add a new commodity that can be used in the string operations.
- `clearUserDefinedCommodities()` remove all user defined commodities from the library.
- `disableUserDefinedCommodities()` there is a performance hit if custom commodities are used so they can be disabled completely if desired.
- `disableUserDefinedCommodities()` there is a (likely small) performance hit in string conversions if custom commodities are used so they can be disabled completely if desired.
- `enableUserDefinedCommodities()` enable the use of UserDefinedCommodities. they are enabled by default.

#### Other unit definitions
Expand Down
6 changes: 5 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ target_sources(test_ucum PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty/xml/tinyxml2.cpp
target_include_directories(test_ucum PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty)
target_compile_definitions(test_ucum PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")


target_sources(test_udunits PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty/xml/tinyxml2.cpp ${CMAKE_SOURCE_DIR}/ThirdParty/xml/tinyxml2.h)
target_include_directories(test_udunits PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty)
target_compile_definitions(test_udunits PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")

if (NOT MSVC)
target_compile_options(test_ucum PRIVATE -Wno-double-promotion)
target_compile_options(test_udunits PRIVATE -Wno-double-promotion)
endif()
add_executable(examples_test examples_test.cpp)
target_link_libraries(examples_test PRIVATE units::units)
target_compile_definitions(examples_test PRIVATE ${TARGET_SPECIAL_COMPILER_FLAGS})
Expand Down
4 changes: 2 additions & 2 deletions test/test_leadingNumbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ TEST(leadingNumbers, power)
EXPECT_GE(index, 3);

res = testLeadingNumber("10.0^-2", index);
EXPECT_EQ(res, 0.01);
EXPECT_DOUBLE_EQ(res, 0.01);

res = testLeadingNumber("3.1^4.3houses", index);
EXPECT_EQ(res, pow(3.1, 4.3));
EXPECT_DOUBLE_EQ(res, pow(3.1, 4.3));
EXPECT_GE(index, 7);
}

Expand Down
9 changes: 3 additions & 6 deletions test/test_measurement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ SPDX-License-Identifier: BSD-3-Clause

#include <type_traits>

template class units::measurement_type<double>;
template class units::fixed_measurement_type<double>;

using namespace units;
TEST(Measurement, ops)
{
Expand Down Expand Up @@ -139,9 +136,9 @@ TEST(Measurement, conversions)
using namespace units;
TEST(fixedMeasurement, ops)
{
fixed_measurement_type<double> d1(45.0, m);
fixed_measurement_type<double> d2(79, m);
fixed_measurement_type<double> d3(79 * m);
fixed_measurement d1(45.0, m);
fixed_measurement d2(79, m);
fixed_measurement d3(79 * m);

auto area = d1 * d2;

Expand Down
3 changes: 0 additions & 3 deletions test/test_measurement_strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,4 @@ TEST(MeasurementToString, simple)
EXPECT_EQ(to_string(pm), "45 m");
auto meas = 45.0 * m;
EXPECT_EQ(to_string(meas), "45 m");

measurement_f meas_f2(45.0f, m);
EXPECT_EQ(to_string(meas_f2), "45 m");
}
4 changes: 2 additions & 2 deletions test/test_random_round_trip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ TEST(randomRoundTrip, basic)
for (auto ii = 0; ii < 6000; ++ii) {
auto start = distribution(generator);
detail::unit_data unitdata(nullptr);
memcpy(&unitdata, &start, 4);
memcpy(static_cast<void*>(&unitdata), &start, 4);
auto startunit = unit(unitdata);
auto str = to_string(startunit);
auto resunit = unit_cast(unit_from_string(str));
Expand All @@ -37,7 +37,7 @@ TEST_P(rtrip, testConversions)
{
unsigned int start = GetParam();
detail::unit_data unitdata(nullptr);
memcpy(&unitdata, &start, 4);
memcpy(static_cast<void*>(&unitdata), &start, 4);
auto startunit = unit(unitdata);
auto str = to_string(startunit);
auto resunit = unit_cast(unit_from_string(str));
Expand Down
10 changes: 0 additions & 10 deletions units/units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -972,16 +972,6 @@ std::string to_string(measurement measure, uint32_t match_flags)
return ss.str();
}

std::string to_string(measurement_f measure, uint32_t match_flags)
{
std::stringstream ss;
ss.precision(7);
ss << measure.value();
ss << ' ';
ss << to_string(measure.units(), match_flags);
return ss.str();
}

/// Generate the prefix multiplier for SI units
static double getPrefixMultiplier(char p)
{
Expand Down
Loading

0 comments on commit 38ddc19

Please sign in to comment.