1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
2 // unit/quantity manipulation and conversion
3 //
4 // Copyright (C) 2003-2008 Matthias Christian Schabel
5 // Copyright (C) 2008 Steven Watanabe
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10
11 #ifndef BOOST_UNITS_CONSTANTS_HPP
12 #define BOOST_UNITS_CONSTANTS_HPP
13
14 #include <boost/config/no_tr1/cmath.hpp>
15 #include <iosfwd>
16 #include <iomanip>
17
18 #include <boost/io/ios_state.hpp>
19
20 #include <boost/units/static_constant.hpp>
21 #include <boost/units/units_fwd.hpp>
22 #include <boost/units/operators.hpp>
23 #include <boost/units/static_rational.hpp>
24 #include <boost/units/detail/one.hpp>
25
26 namespace boost {
27
28 namespace units {
29
30 template<class Base>
31 struct constant
32 {
33 typedef typename Base::value_type value_type;
operator value_typeboost::units::constant34 BOOST_CONSTEXPR operator value_type() const { return Base().value(); }
valueboost::units::constant35 BOOST_CONSTEXPR value_type value() const { return Base().value(); }
uncertaintyboost::units::constant36 BOOST_CONSTEXPR value_type uncertainty() const { return Base().uncertainty(); }
lower_boundboost::units::constant37 BOOST_CONSTEXPR value_type lower_bound() const { return Base().lower_bound(); }
upper_boundboost::units::constant38 BOOST_CONSTEXPR value_type upper_bound() const { return Base().upper_bound(); }
39 };
40
41 template<class Base>
42 struct physical_constant
43 {
44 typedef typename Base::value_type value_type;
operator value_typeboost::units::physical_constant45 BOOST_CONSTEXPR operator value_type() const { return Base().value(); }
valueboost::units::physical_constant46 BOOST_CONSTEXPR value_type value() const { return Base().value(); }
uncertaintyboost::units::physical_constant47 BOOST_CONSTEXPR value_type uncertainty() const { return Base().uncertainty(); }
lower_boundboost::units::physical_constant48 BOOST_CONSTEXPR value_type lower_bound() const { return Base().lower_bound(); }
upper_boundboost::units::physical_constant49 BOOST_CONSTEXPR value_type upper_bound() const { return Base().upper_bound(); }
50 };
51
52 #define BOOST_UNITS_DEFINE_HELPER(name, symbol, template_name) \
53 \
54 template<class T, class Arg1, class Arg2> \
55 struct name ## _typeof_helper<constant<T>, template_name<Arg1, Arg2> >\
56 { \
57 typedef typename name ## _typeof_helper<typename T::value_type, template_name<Arg1, Arg2> >::type type;\
58 }; \
59 \
60 template<class T, class Arg1, class Arg2> \
61 struct name ## _typeof_helper<template_name<Arg1, Arg2>, constant<T> >\
62 { \
63 typedef typename name ## _typeof_helper<template_name<Arg1, Arg2>, typename T::value_type>::type type;\
64 }; \
65 \
66 template<class T, class Arg1, class Arg2> \
67 BOOST_CONSTEXPR \
68 typename name ## _typeof_helper<typename T::value_type, template_name<Arg1, Arg2> >::type \
69 operator symbol(const constant<T>& t, const template_name<Arg1, Arg2>& u)\
70 { \
71 return(t.value() symbol u); \
72 } \
73 \
74 template<class T, class Arg1, class Arg2> \
75 BOOST_CONSTEXPR \
76 typename name ## _typeof_helper<template_name<Arg1, Arg2>, typename T::value_type>::type \
77 operator symbol(const template_name<Arg1, Arg2>& u, const constant<T>& t)\
78 { \
79 return(u symbol t.value()); \
80 }
81
82 BOOST_UNITS_DEFINE_HELPER(add, +, unit)
83 BOOST_UNITS_DEFINE_HELPER(add, +, quantity)
84 BOOST_UNITS_DEFINE_HELPER(subtract, -, unit)
85 BOOST_UNITS_DEFINE_HELPER(subtract, -, quantity)
86 BOOST_UNITS_DEFINE_HELPER(multiply, *, unit)
87 BOOST_UNITS_DEFINE_HELPER(multiply, *, quantity)
88 BOOST_UNITS_DEFINE_HELPER(divide, /, unit)
89 BOOST_UNITS_DEFINE_HELPER(divide, /, quantity)
90
91 #undef BOOST_UNITS_DEFINE_HELPER
92
93 #define BOOST_UNITS_DEFINE_HELPER(name, symbol) \
94 \
95 template<class T1, class T2> \
96 struct name ## _typeof_helper<constant<T1>, constant<T2> > \
97 { \
98 typedef typename name ## _typeof_helper<typename T1::value_type, typename T2::value_type>::type type;\
99 }; \
100 \
101 template<class T1, class T2> \
102 BOOST_CONSTEXPR \
103 typename name ## _typeof_helper<typename T1::value_type, typename T2::value_type>::type \
104 operator symbol(const constant<T1>& t, const constant<T2>& u) \
105 { \
106 return(t.value() symbol u.value()); \
107 } \
108 \
109 template<class T1, class T2> \
110 struct name ## _typeof_helper<constant<T1>, T2> \
111 { \
112 typedef typename name ## _typeof_helper<typename T1::value_type, T2>::type type;\
113 }; \
114 \
115 template<class T1, class T2> \
116 struct name ## _typeof_helper<T1, constant<T2> > \
117 { \
118 typedef typename name ## _typeof_helper<T1, typename T2::value_type>::type type;\
119 }; \
120 \
121 template<class T1, class T2> \
122 BOOST_CONSTEXPR \
123 typename name ## _typeof_helper<typename T1::value_type, T2>::type \
124 operator symbol(const constant<T1>& t, const T2& u) \
125 { \
126 return(t.value() symbol u); \
127 } \
128 \
129 template<class T1, class T2> \
130 BOOST_CONSTEXPR \
131 typename name ## _typeof_helper<T1, typename T2::value_type>::type \
132 operator symbol(const T1& t, const constant<T2>& u) \
133 { \
134 return(t symbol u.value()); \
135 }
136
137 BOOST_UNITS_DEFINE_HELPER(add, +)
138 BOOST_UNITS_DEFINE_HELPER(subtract, -)
139 BOOST_UNITS_DEFINE_HELPER(multiply, *)
140 BOOST_UNITS_DEFINE_HELPER(divide, /)
141
142 #undef BOOST_UNITS_DEFINE_HELPER
143
144 #define BOOST_UNITS_DEFINE_HELPER(name, symbol) \
145 \
146 template<class T1> \
147 struct name ## _typeof_helper<constant<T1>, one> \
148 { \
149 typedef typename name ## _typeof_helper<typename T1::value_type, one>::type type;\
150 }; \
151 \
152 template<class T2> \
153 struct name ## _typeof_helper<one, constant<T2> > \
154 { \
155 typedef typename name ## _typeof_helper<one, typename T2::value_type>::type type;\
156 }; \
157 \
158 template<class T1> \
159 BOOST_CONSTEXPR \
160 typename name ## _typeof_helper<typename T1::value_type, one>::type \
161 operator symbol(const constant<T1>& t, const one& u) \
162 { \
163 return(t.value() symbol u); \
164 } \
165 \
166 template<class T2> \
167 BOOST_CONSTEXPR \
168 typename name ## _typeof_helper<one, typename T2::value_type>::type \
169 operator symbol(const one& t, const constant<T2>& u) \
170 { \
171 return(t symbol u.value()); \
172 }
173
174 BOOST_UNITS_DEFINE_HELPER(multiply, *)
175 BOOST_UNITS_DEFINE_HELPER(divide, /)
176
177 #undef BOOST_UNITS_DEFINE_HELPER
178
179 template<class T1, long N, long D>
180 struct power_typeof_helper<constant<T1>, static_rational<N,D> >
181 {
182 typedef power_typeof_helper<typename T1::value_type, static_rational<N,D> > base;
183 typedef typename base::type type;
valueboost::units::power_typeof_helper184 static BOOST_CONSTEXPR type value(const constant<T1>& arg)
185 {
186 return base::value(arg.value());
187 }
188 };
189
190 #define BOOST_UNITS_DEFINE_HELPER(name, symbol) \
191 \
192 template<class T1, class E> \
193 struct name ## _typeof_helper<constant<T1> > \
194 { \
195 typedef typename name ## _typeof_helper<typename T1::value_type, E>::type type;\
196 }; \
197 \
198 template<class T1> \
199 BOOST_CONSTEXPR \
200 typename name ## _typeof_helper<typename T1::value_type, one>::type \
201 operator symbol(const constant<T1>& t, const one& u) \
202 { \
203 return(t.value() symbol u); \
204 } \
205 \
206 template<class T2> \
207 BOOST_CONSTEXPR \
208 typename name ## _typeof_helper<one, typename T2::value_type>::type \
209 operator symbol(const one& t, const constant<T2>& u) \
210 { \
211 return(t symbol u.value()); \
212 }
213
214 #define BOOST_UNITS_PHYSICAL_CONSTANT(name, type, value_, uncertainty_) \
215 struct name ## _t { \
216 typedef type value_type; \
217 BOOST_CONSTEXPR operator value_type() const { return value_; } \
218 BOOST_CONSTEXPR value_type value() const { return value_; } \
219 BOOST_CONSTEXPR value_type uncertainty() const { return uncertainty_; } \
220 BOOST_CONSTEXPR value_type lower_bound() const { return value_-uncertainty_; } \
221 BOOST_CONSTEXPR value_type upper_bound() const { return value_+uncertainty_; } \
222 }; \
223 BOOST_UNITS_STATIC_CONSTANT(name, boost::units::constant<boost::units::physical_constant<name ## _t> >) = { }
224
225 // stream output
226 template<class Char, class Traits, class Y>
227 inline
operator <<(std::basic_ostream<Char,Traits> & os,const physical_constant<Y> & val)228 std::basic_ostream<Char,Traits>& operator<<(std::basic_ostream<Char,Traits>& os,const physical_constant<Y>& val)
229 {
230 boost::io::ios_precision_saver precision_saver(os);
231 //boost::io::ios_width_saver width_saver(os);
232 boost::io::ios_flags_saver flags_saver(os);
233
234 //os << std::setw(21);
235 typedef typename Y::value_type value_type;
236
237 if (val.uncertainty() > value_type())
238 {
239 const double relative_uncertainty = std::abs(val.uncertainty()/val.value());
240
241 const double exponent = std::log10(relative_uncertainty);
242 const long digits_of_precision = static_cast<long>(std::ceil(std::abs(exponent)))+3;
243
244 // should try to replicate NIST CODATA syntax
245 os << std::setprecision(digits_of_precision)
246 //<< std::setw(digits_of_precision+8)
247 //<< std::scientific
248 << val.value();
249 // << long(10*(relative_uncertainty/std::pow(Y(10),Y(exponent))));
250
251 os << " (rel. unc. = "
252 << std::setprecision(1)
253 //<< std::setw(7)
254 << std::scientific
255 << relative_uncertainty << ")";
256 }
257 else
258 {
259 os << val.value() << " (exact)";
260 }
261
262 return os;
263 }
264
265 // stream output
266 template<class Char, class Traits, class Y>
267 inline
operator <<(std::basic_ostream<Char,Traits> & os,const constant<Y> &)268 std::basic_ostream<Char,Traits>& operator<<(std::basic_ostream<Char,Traits>& os,const constant<Y>&)
269 {
270 os << Y();
271 return os;
272 }
273
274 } // namespace units
275
276 } // namespace boost
277
278 #endif // BOOST_UNITS_CONSTANTS_HPP
279