CORSIKA  @c8_version@
The framework to simulate particle cascades for astroparticle physics
quantity_io_engineering.hpp
1 
23 #ifndef PHYS_UNITS_QUANTITY_IO_ENGINEERING_HPP_INCLUDED
24 #define PHYS_UNITS_QUANTITY_IO_ENGINEERING_HPP_INCLUDED
25 
27 
28 #include <cmath>
29 #include <iomanip>
30 #include <limits>
31 #include <sstream>
32 
33 /*
34  * Note: micro, may not work everywhere, so you can define a glyph yourself:
35  */
36 #ifndef ENG_FORMAT_MICRO_GLYPH
37 # define ENG_FORMAT_MICRO_GLYPH "u"
38 #endif
39 
41 
42 namespace phys {
43 
45 
46 namespace units {
47 
49 
50 namespace detail {
51 
52 char const * const prefixes[/*exp*/][2][9] =
53 {
54  {
55  { "", "m", ENG_FORMAT_MICRO_GLYPH
56  , "n", "p", "f", "a", "z", "y", },
57  { "", "k", "M", "G", "T", "P", "E", "Z", "Y", },
58  },
59  {
60  { "e0", "e-3", "e-6", "e-9", "e-12", "e-15", "e-18", "e-21", "e-24", },
61  { "e0", "e3", "e6", "e9", "e12", "e15", "e18", "e21", "e24", },
62  },
63 };
64 
65 template<typename T, size_t N>
66 constexpr size_t dimenson_of( T(&)[N] )
67 {
68  return N;
69 }
70 
71 constexpr int prefix_count = dimenson_of( prefixes[false][false] );
72 
73 inline int sign( int const value )
74 {
75  return value == 0 ? +1 : value / std::abs( value );
76 }
77 
78 inline bool iszero( double const value )
79 {
80  return FP_ZERO == std::fpclassify( value );
81 }
82 
83 inline long degree_of( double const value )
84 {
85  return iszero( value ) ? 0 : std::lrint( std::floor( std::log10( std::abs( value ) ) / 3) );
86 }
87 
88 inline int precision( double const scaled, int const digits )
89 {
90  return iszero( scaled ) ? digits - 1 : digits - std::log10( std::abs( scaled ) ) - 2 * std::numeric_limits<double>::epsilon();
91 }
92 
93 inline std::string prefix_or_exponent( bool const exponential, int const degree )
94 {
95  return std::string( exponential || 0 == degree ? "" : " " ) + prefixes[ exponential ][ sign(degree) > 0 ][ std::abs( degree ) ];
96 }
97 
98 inline std::string exponent( int const degree )
99 {
100  std::ostringstream os;
101  os << "e" << 3 * degree;
102  return os.str();
103 }
104 
105 inline std::string bracket( std::string const unit )
106 {
107  return std::string::npos != unit.find_first_of( "+- " ) ? "(" + unit + ")" : unit;
108 }
109 
110 } // anonymous namespace
111 
115 inline std::string
116 to_engineering_string( double const value, int const digits = 3, bool exponential = false, bool const showpos = false, std::string const unit = "" )
117 {
118  using namespace detail;
119 
120  if ( std::isnan( value ) ) return "NaN";
121  else if ( std::isinf( value ) ) return "INFINITE";
122 
123  const int degree = degree_of( value );
124 
125  std::string factor;
126 
127  if ( std::abs( degree ) < prefix_count )
128  {
129  factor = prefix_or_exponent( exponential, degree );
130  }
131  else
132  {
133  exponential = true;
134  factor = exponent( degree );
135  }
136 
137  std::ostringstream os;
138 
139  const double scaled = value * std::pow( 1000.0, -degree );
140 
141  const std::string space = ( 0 == degree || exponential ) && unit.length() ? " ":"";
142 
143  os << std::fixed << (showpos ? std::showpos : std::noshowpos) << std::setprecision( precision(scaled, digits) ) << scaled << factor << space << bracket( unit );
144 
145  return os.str();
146 }
147 
148 namespace io {
149 namespace eng {
150 
151 template< typename Dims, typename T >
152 std::string to_string( quantity<Dims, T> const & q, int const digits = 3, bool const exponential = false, bool const showpos = false )
153 {
154  return to_engineering_string( q.magnitude(), digits, exponential, showpos, to_unit_symbol( q ) );
155 }
156 
157 template< typename Dims, typename T >
158 inline std::ostream & operator<<( std::ostream & os, quantity< Dims, T > const & q )
159 {
160  return os << to_string( q );
161 }
162 
163 } // namespace eng
164 } // namespace io
165 
166 }} // namespace phys::units
167 
168 #endif // PHYS_UNITS_QUANTITY_IO_ENGINEERING_HPP_INCLUDED
169 
170 /*
171  * end of file
172  */
173 
quantity< D, X > constexpr abs(quantity< D, X > const &x)
absolute value.
Definition: quantity.hpp:632
std::string to_engineering_string(double const value, int const digits=3, bool exponential=false, bool const showpos=false, std::string const unit="")
convert real number to prefixed or exponential notation, optionally followed by a unit...
std::string to_unit_symbol(quantity< Dims, T > const &)
unit symbol.
namespace phys.
std::string to_string(long double const value)
string representation of value.
class "quantity" is the heart of the library.
Definition: quantity.hpp:54
constexpr value_type magnitude() const
the quantity&#39;s magnitude.
Definition: quantity.hpp:346
IO for quantity library.