Skip to content

Instantly share code, notes, and snippets.

@vietlq
Last active August 8, 2017 08:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vietlq/5df7b9ac33a43b655fe30e1ce47a3ef4 to your computer and use it in GitHub Desktop.
Save vietlq/5df7b9ac33a43b655fe30e1ce47a3ef4 to your computer and use it in GitHub Desktop.
Floats and Doubles for Dummies: Understanding Floating Points
php > print((0.1 + 0.8 == 0.9) ? "true" : "false");
true
php > print((0.2 + 0.7 == 0.9) ? "true" : "false");
false
php > print((0.3 + 0.6 == 0.9) ? "true" : "false");
false
php > print((0.4 + 0.5 == 0.9) ? "true" : "false");
true
>>> 0.1 + 0.8 == 0.9
True
>>> 0.2 + 0.7 == 0.9
False
>>> 0.3 + 0.6 == 0.9
False
>>> 0.4 + 0.5 == 0.9
True
irb(main):021:0> 0.1 + 0.8 == 0.9
=> true
irb(main):020:0> 0.2 + 0.7 == 0.9
=> false
irb(main):018:0> 0.3 + 0.6 == 0.9
=> false
irb(main):019:0> 0.4 + 0.5 == 0.9
=> true
#include <limits>
#include <iostream>
template<typename T>
struct name_trait
{
constexpr static auto name = "undefined name_trait";
};
template<>
struct name_trait<float>
{
constexpr static auto name = "float";
};
template<>
struct name_trait<double>
{
constexpr static auto name = "double";
};
template<>
struct name_trait<long double>
{
constexpr static auto name = "long double";
};
template<typename T>
void inspect_type()
{
constexpr auto name = name_trait<T>::name;
std::cout << "std::numeric_limits<" << name << ">::denorm_min() = "
<< std::numeric_limits<T>::denorm_min() << std::endl;
std::cout << "std::numeric_limits<" << name << ">::min() = "
<< std::numeric_limits<T>::min() << std::endl;
std::cout << "std::numeric_limits<" << name << ">::max() = "
<< std::numeric_limits<T>::max() << std::endl;
std::cout << "std::numeric_limits<" << name << ">::epsilon() = "
<< std::numeric_limits<T>::epsilon() << std::endl;
std::cout << "----" << std::endl;
}
int main()
{
inspect_type<float>();
inspect_type<double>();
inspect_type<long double>();
return 0;
}
#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
union float_int
{
float f;
int i;
};
void explore_ulp(int num1)
{
const int num2 = num1 + 1;
float_int conv;
conv.i = num1;
const float float1 = conv.f;
conv.i = num2;
const float float2 = conv.f;
const float diff = std::abs(float1 - float2);
const float float_epsilon = std::numeric_limits<float>::epsilon();
std::cout << "num1 = " << num1 << std::endl;
std::cout << "num2 = " << num2 << std::endl;
std::cout << std::setprecision(20);
std::cout << "float1 = " << float1 << std::endl;
std::cout << "float2 = " << float2 << std::endl;
std::cout << "diff = " << diff << std::endl;
std::cout << "(diff == float_epsilon) is " << (diff == float_epsilon) << std::endl;
std::cout << "----" << std::endl;
}
int main()
{
explore_ulp(0x3f9e0651);
explore_ulp(0x4ceb79a2);
explore_ulp(0x7f7fffff);
return 0;
}
#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
// The example is borrowed from http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
almost_equal(T x, T y, int ulp)
{
// the machine epsilon has to be scaled to the magnitude of the values used
// and multiplied by the desired precision in ULPs (units in the last place)
return (std::abs(x-y) < (
std::numeric_limits<T>::epsilon() *
(std::abs(x) + std::abs(y)) * ulp))
// unless the result is subnormal
|| (std::abs(x-y) < std::numeric_limits<T>::min());
std::cout << "----" << std::endl;
}
void near_equal_example()
{
const float d1 = 0.2000001;
const float d2 = 1 / std::sqrt(5) / std::sqrt(5);
const float diff = std::abs(d1 - d2);
std::cout << std::setprecision(20) << "d1 = " << d1
<< "; d2 = " << d2 << std::endl;
std::cout << "diff = " << diff << std::endl;
if(d1 == d2)
{
std::cout << "d1 == d2" << std::endl;
}
else
{
std::cout << "d1 != d2" << std::endl;
}
for (int ulp = 0; ulp < 4; ++ulp)
{
std::cout << "ulp = " << ulp << ": ";
if(almost_equal(d1, d2, ulp))
{
std::cout << "d1 almost equals d2" << std::endl;
}
else
{
std::cout << "d1 does not almost equal d2" << std::endl;
}
}
}
int main()
{
near_equal_example();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment