Check that the float is within the range of an int before casting.
This commit is contained in:
parent
bda9471c1b
commit
7c2ab1d7de
@ -36,6 +36,7 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@ -670,27 +671,28 @@ namespace Exiv2 {
|
||||
|
||||
Rational floatToRationalCast(float f)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
if (!_finite(f)) {
|
||||
#else
|
||||
if (!std::isfinite(f)) {
|
||||
#endif
|
||||
return {f > 0 ? 1 : -1, 0};
|
||||
|
||||
// Convert f to double because it simplifies the "in_range" check
|
||||
// below. (INT_MAX can be represented accurately as a double, but
|
||||
// gets rounded when it's converted to float.)
|
||||
const double d = f;
|
||||
const bool in_range = INT_MIN <= d && d <= INT_MAX;
|
||||
if (!in_range) {
|
||||
return {d > 0 ? 1 : -1, 0};
|
||||
}
|
||||
// Beware: primitive conversion algorithm
|
||||
int32_t den = 1000000;
|
||||
const long f_as_long = static_cast<long>(f);
|
||||
if (Safe::abs(f_as_long) > 2147) {
|
||||
const long d_as_long = static_cast<long>(d);
|
||||
if (Safe::abs(d_as_long) > 2147) {
|
||||
den = 10000;
|
||||
}
|
||||
if (Safe::abs(f_as_long) > 214748) {
|
||||
if (Safe::abs(d_as_long) > 214748) {
|
||||
den = 100;
|
||||
}
|
||||
if (Safe::abs(f_as_long) > 21474836) {
|
||||
if (Safe::abs(d_as_long) > 21474836) {
|
||||
den = 1;
|
||||
}
|
||||
const float rnd = f >= 0 ? 0.5F : -0.5F;
|
||||
const auto nom = static_cast<int32_t>(f * den + rnd);
|
||||
const auto nom = static_cast<int32_t>(std::round(d * den));
|
||||
const int32_t g = gcd(nom, den);
|
||||
|
||||
return {nom / g, den / g};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user