Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bfbe5f19e0ce
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c86fab23471c
Choose a head ref
  • 9 commits
  • 5 files changed
  • 1 contributor

Commits on Aug 14, 2019

  1. A new class.

    pleroy committed Aug 14, 2019
    Copy the full SHA
    2981ff3 View commit details
  2. A test.

    pleroy committed Aug 14, 2019
    Copy the full SHA
    b908ff8 View commit details

Commits on Aug 15, 2019

  1. Copy the full SHA
    77dd364 View commit details
  2. Template specialization.

    pleroy committed Aug 15, 2019
    Copy the full SHA
    b4c17c6 View commit details
  3. A test for units.

    pleroy committed Aug 15, 2019
    Copy the full SHA
    08773e9 View commit details
  4. Output.

    pleroy committed Aug 15, 2019
    Copy the full SHA
    d32baf5 View commit details

Commits on Aug 16, 2019

  1. After egg's review.

    pleroy committed Aug 16, 2019
    Copy the full SHA
    4232c57 View commit details

Commits on Aug 17, 2019

  1. Egg's 2nd review and lint.

    pleroy committed Aug 17, 2019
    Copy the full SHA
    812dfd8 View commit details
  2. Merge pull request #2285 from pleroy/2269

    A class to represent an approximate quantity
    pleroy authored Aug 17, 2019
    Copy the full SHA
    c86fab2 View commit details
148 changes: 148 additions & 0 deletions testing_utilities/approximate_quantity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#pragma once

#include <string>
#include <string_view>

#include "quantities/named_quantities.hpp"
#include "quantities/quantities.hpp"

namespace principia {
namespace testing_utilities {
namespace internal_approximate_quantity {

using quantities::Product;
using quantities::Quantity;
using quantities::Quotient;

template<typename Quantity>
class ApproximateQuantity;

template<typename Dimensions>
class ApproximateQuantity<Quantity<Dimensions>> {
public:
Quantity<Dimensions> min() const;
Quantity<Dimensions> max() const;

std::string DebugString() const;

private:
ApproximateQuantity(std::string const& representation,
int ulp,
double min_multiplier,
double max_multiplier,
Quantity<Dimensions> const& unit);

// The original representation.
std::string representation_;
int ulp_;

// The interval for the approximate quantity, expressed as multiples of unit_.
double min_multiplier_;
double max_multiplier_;

// The unit for the approximate quantity. Could for instance be Degree for an
// angle.
Quantity<Dimensions> unit_;

template<typename Left, typename RDimensions>
friend ApproximateQuantity<Product<Left, Quantity<RDimensions>>> operator*(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);
template<typename Left, typename RDimensions>
friend ApproximateQuantity<Quotient<Left, Quantity<RDimensions>>> operator/(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);
};

template<>
class ApproximateQuantity<double> {
public:
static ApproximateQuantity<double> Parse(std::string_view representation,
int ulp);

double min() const;
double max() const;

std::string DebugString() const;

private:
ApproximateQuantity(std::string_view representation,
int ulp,
double min_multiplier,
double max_multiplier);

// The original representation.
std::string representation_;
int ulp_;

// The interval for the approximate quantity.
double min_multiplier_;
double max_multiplier_;

static constexpr double unit_ = 1;

template<typename Left, typename RDimensions>
friend ApproximateQuantity<Product<Left, Quantity<RDimensions>>> operator*(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);
template<typename Left, typename RDimensions>
friend ApproximateQuantity<Quotient<Left, Quantity<RDimensions>>> operator/(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);
};

template<typename Left, typename RDimensions>
ApproximateQuantity<Product<Left, Quantity<RDimensions>>> operator*(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);
template<typename Left, typename RDimensions>
ApproximateQuantity<Quotient<Left, Quantity<RDimensions>>> operator/(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right);

template<typename Quantity>
std::ostream& operator<<(std::ostream& out,
ApproximateQuantity<Quantity> const& q);

// The 🄐 to 🄕 operators are only for hexadecimal literals.
ApproximateQuantity<double> operator""_⑴(char const* representation);
ApproximateQuantity<double> operator""_⑵(char const* representation);
ApproximateQuantity<double> operator""_⑶(char const* representation);
ApproximateQuantity<double> operator""_⑷(char const* representation);
ApproximateQuantity<double> operator""_⑸(char const* representation);
ApproximateQuantity<double> operator""_⑹(char const* representation);
ApproximateQuantity<double> operator""_⑺(char const* representation);
ApproximateQuantity<double> operator""_⑻(char const* representation);
ApproximateQuantity<double> operator""_⑼(char const* representation);
ApproximateQuantity<double> operator""_🄐(char const* representation);
ApproximateQuantity<double> operator""_🄑(char const* representation);
ApproximateQuantity<double> operator""_🄒(char const* representation);
ApproximateQuantity<double> operator""_🄓(char const* representation);
ApproximateQuantity<double> operator""_🄔(char const* representation);
ApproximateQuantity<double> operator""_🄕(char const* representation);

} // namespace internal_approximate_quantity

using internal_approximate_quantity::ApproximateQuantity;
using internal_approximate_quantity::operator*;
using internal_approximate_quantity::operator/;
using internal_approximate_quantity::operator""_⑴;
using internal_approximate_quantity::operator""_⑵;
using internal_approximate_quantity::operator""_⑶;
using internal_approximate_quantity::operator""_⑷;
using internal_approximate_quantity::operator""_⑸;
using internal_approximate_quantity::operator""_⑹;
using internal_approximate_quantity::operator""_⑺;
using internal_approximate_quantity::operator""_⑻;
using internal_approximate_quantity::operator""_⑼;
using internal_approximate_quantity::operator""_🄐;
using internal_approximate_quantity::operator""_🄑;
using internal_approximate_quantity::operator""_🄒;
using internal_approximate_quantity::operator""_🄓;
using internal_approximate_quantity::operator""_🄔;
using internal_approximate_quantity::operator""_🄕;

} // namespace testing_utilities
} // namespace principia

#include "testing_utilities/approximate_quantity_body.hpp"
162 changes: 162 additions & 0 deletions testing_utilities/approximate_quantity_body.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#pragma once

#include <optional>
#include <string>

#include "testing_utilities/approximate_quantity.hpp"

namespace principia {
namespace testing_utilities {
namespace internal_approximate_quantity {

template<typename Dimensions>
Quantity<Dimensions> ApproximateQuantity<Quantity<Dimensions>>::min() const {
return min_multiplier_ * unit_;
}

template<typename Dimensions>
Quantity<Dimensions> ApproximateQuantity<Quantity<Dimensions>>::max() const {
return max_multiplier_ * unit_;
}

template<typename Dimensions>
std::string ApproximateQuantity<Quantity<Dimensions>>::DebugString() const {
return representation_ + "(" + std::to_string(ulp_) + ") * " +
quantities::DebugString(unit_);
}

template<typename Dimensions>
ApproximateQuantity<Quantity<Dimensions>>::ApproximateQuantity(
std::string const& representation,
int const ulp,
double const min_multiplier,
double const max_multiplier,
Quantity<Dimensions> const& unit)
: representation_(representation),
ulp_(ulp),
min_multiplier_(min_multiplier),
max_multiplier_(max_multiplier),
unit_(unit) {}

ApproximateQuantity<double> ApproximateQuantity<double>::Parse(
std::string_view const representation,
int const ulp) {
std::string error_representation(representation);
std::optional<int> last_digit_index;
bool const is_hexadecimal =
error_representation.size() >= 2 &&
error_representation[0] == '0' &&
(error_representation[1] == 'x' || error_representation[1] == 'X');

// Replace all the digits before the exponent by zeroes, except for the last
// one which get the number of ulps. The result is the string representation
// of the error on the quantity.
for (int i = 0; i < error_representation.size(); ++i) {
char const c = error_representation[i];
if (c >= '1' && c <= '9') {
error_representation[i] = '0';
last_digit_index = i;
} else if (is_hexadecimal &&
((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
error_representation[i] = '0';
last_digit_index = i;
} else if ((!is_hexadecimal && (c == 'e' || c == 'E')) ||
(is_hexadecimal && (c == 'p' || c == 'P'))) {
CHECK(last_digit_index.has_value());
break;
}
}
if (ulp <= 9) {
error_representation[*last_digit_index] = '0' + ulp;
} else {
CHECK(is_hexadecimal);
error_representation[*last_digit_index] = 'A' + ulp - 10;
}
double const value = std::strtod(representation.data(), nullptr);
double const error = std::strtod(error_representation.c_str(), nullptr);
return ApproximateQuantity<double>(representation,
ulp,
value - error,
value + error);
}

double ApproximateQuantity<double>::min() const {
return min_multiplier_;
}

double ApproximateQuantity<double>::max() const {
return max_multiplier_;
}

std::string ApproximateQuantity<double>::DebugString() const {
return representation_ + "(" + std::to_string(ulp_) + ")";
}

ApproximateQuantity<double>::ApproximateQuantity(
std::string_view const representation,
int const ulp,
double const min_multiplier,
double const max_multiplier)
: representation_(representation),
ulp_(ulp),
min_multiplier_(min_multiplier),
max_multiplier_(max_multiplier) {}

template<typename Left, typename RDimensions>
ApproximateQuantity<Product<Left, Quantity<RDimensions>>> operator*(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right) {
return ApproximateQuantity<Product<Left, Quantity<RDimensions>>>(
left.representation_,
left.ulp_,
left.min_multiplier_,
left.max_multiplier_,
left.unit_ * right);
}

template<typename Left, typename RDimensions>
ApproximateQuantity<Quotient<Left, Quantity<RDimensions>>> operator/(
ApproximateQuantity<Left> const& left,
Quantity<RDimensions> const& right) {
return ApproximateQuantity<Quotient<Left, Quantity<RDimensions>>>(
left.representation_,
left.ulp_,
left.min_multiplier_,
left.max_multiplier_,
left.unit_ / right);
}

template<typename Quantity>
std::ostream& operator<<(std::ostream& out,
ApproximateQuantity<Quantity> const& q) {
out << q.DebugString();
return out;
}

#define PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(symbol, ulp) \
ApproximateQuantity<double> operator""_##symbol( \
char const* const representation) { \
return ApproximateQuantity<double>::Parse(representation, ulp); \
}

PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑴, 1)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑵, 2)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑶, 3)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑷, 4)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑸, 5)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑹, 6)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑺, 7)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑻, 8)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(⑼, 9)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄐, 0xA)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄑, 0xB)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄒, 0xC)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄓, 0xD)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄔, 0xE)
PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION(🄕, 0xF)

#undef PRINCIPIA_APPROXIMATE_QUANTITY_OPERATOR_DEFINITION

} // namespace internal_approximate_quantity
} // namespace testing_utilities
} // namespace principia
Loading