高于给定值的最小可表达值
Smallest expressible value above given value
给定一个定义为
的变量
T x;
其中 T
是通用算术类型(即 std::is_arithmetic<T>::value
),是否有一个简单的表达式(例如来自 std::numeric_limits
的东西)计算为最低值 y
可以用 T
表示,这样 y
> x
?
(即一种广义增量..)
<cmath>
header 的 std::nexttoward()
会这样做。它接受 float、double、long double 或整数类型,并且 returns 其第二个参数方向上的下一个值。
所以,给出这样的代码:
T my_val = some_input; // float, double, int, etc.
T next = std::nexttoward(my_val, std::numeric_limits<T>::max());`
如果my_val
是1.0f,next
将是1之后的下一个最大的浮点数;如果 my_val
是整数 2,你会得到 3,等等
(请注意,这里有很多关于数字溢出的细则,上面链接的 CppReference 页面对此进行了讨论。总而言之,不要将 std::numeric_limits<T>::max()
传递给第一个参数。)
#include <type_traits>
#include <limits>
#include <iostream>
/*
NOTE: Untested code for 'proof' of concept only.
This will cover all the is_integral<T> except bool.
This should probably be a set of free functions rather than a class
but just to check out the idea. Class should have constraints but as
the final implementation should probably be free functions they are
omitted.
*/
template<typename T>
class GLB{
public:
using limits = std::numeric_limits<T>;
static T get(const T& value){
return value == limits::max() ? limits::max() : value + static_cast<T>(1);
}
};
int main(int, char**){
std::cout << GLB<int>::get(42) << '\n';
std::cout << GLB<unsigned>::get(42) << '\n';
std::cout << GLB<wchar_t>::get(42) << '\n';
return 0;
}
/*
That was the easy bit now what about the floating point numbers.
*/
胡闹的时候scur3指出cmath可以解浮点数。所以需要一些打字和一些测试。
您可以使用 std::nextafter
.
请注意,我在这里使用 std::numeric_limits<Floating>::max()
,如果您想要无穷大的有意义的行为,您可能需要修改代码。
#include <iostream>
#include <limits>
#include <cmath>
#include <type_traits>
#include <iomanip>
template <typename Floating,
std::enable_if_t<std::is_arithmetic_v<Floating> && !std::is_integral_v<Floating>, bool> = false>
Floating generic_next_val(Floating val) {
return std::nextafter(val, std::numeric_limits<Floating>::max());
}
template <typename Integral,
std::enable_if_t<std::is_arithmetic_v<Integral> && std::is_integral_v<Integral>, int> = 0>
Integral generic_next_val(Integral val) {
return static_cast<Integral>(val + static_cast<Integral>(1));
}
int main() {
int a = 1;
float f = 0.0f;
std::cout << std::setprecision(20) << generic_next_val(f) << " " << generic_next_val(a) << std::endl;
return 0;
}
给定一个定义为
的变量T x;
其中 T
是通用算术类型(即 std::is_arithmetic<T>::value
),是否有一个简单的表达式(例如来自 std::numeric_limits
的东西)计算为最低值 y
可以用 T
表示,这样 y
> x
?
(即一种广义增量..)
<cmath>
header 的 std::nexttoward()
会这样做。它接受 float、double、long double 或整数类型,并且 returns 其第二个参数方向上的下一个值。
所以,给出这样的代码:
T my_val = some_input; // float, double, int, etc.
T next = std::nexttoward(my_val, std::numeric_limits<T>::max());`
如果my_val
是1.0f,next
将是1之后的下一个最大的浮点数;如果 my_val
是整数 2,你会得到 3,等等
(请注意,这里有很多关于数字溢出的细则,上面链接的 CppReference 页面对此进行了讨论。总而言之,不要将 std::numeric_limits<T>::max()
传递给第一个参数。)
#include <type_traits>
#include <limits>
#include <iostream>
/*
NOTE: Untested code for 'proof' of concept only.
This will cover all the is_integral<T> except bool.
This should probably be a set of free functions rather than a class
but just to check out the idea. Class should have constraints but as
the final implementation should probably be free functions they are
omitted.
*/
template<typename T>
class GLB{
public:
using limits = std::numeric_limits<T>;
static T get(const T& value){
return value == limits::max() ? limits::max() : value + static_cast<T>(1);
}
};
int main(int, char**){
std::cout << GLB<int>::get(42) << '\n';
std::cout << GLB<unsigned>::get(42) << '\n';
std::cout << GLB<wchar_t>::get(42) << '\n';
return 0;
}
/*
That was the easy bit now what about the floating point numbers.
*/
胡闹的时候scur3指出cmath可以解浮点数。所以需要一些打字和一些测试。
您可以使用 std::nextafter
.
请注意,我在这里使用 std::numeric_limits<Floating>::max()
,如果您想要无穷大的有意义的行为,您可能需要修改代码。
#include <iostream>
#include <limits>
#include <cmath>
#include <type_traits>
#include <iomanip>
template <typename Floating,
std::enable_if_t<std::is_arithmetic_v<Floating> && !std::is_integral_v<Floating>, bool> = false>
Floating generic_next_val(Floating val) {
return std::nextafter(val, std::numeric_limits<Floating>::max());
}
template <typename Integral,
std::enable_if_t<std::is_arithmetic_v<Integral> && std::is_integral_v<Integral>, int> = 0>
Integral generic_next_val(Integral val) {
return static_cast<Integral>(val + static_cast<Integral>(1));
}
int main() {
int a = 1;
float f = 0.0f;
std::cout << std::setprecision(20) << generic_next_val(f) << " " << generic_next_val(a) << std::endl;
return 0;
}