blob: 2c3371b2ab64b94e61096bd0dcf92cc316835d83 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
* \class vespalib::FloatingPointType
* \ingroup object
*
* \brief Wrapper class for floating point types taking care of comparisons.
*
* Due to floating point values not being able to represent a lot of numbers
* exactly, one should always compare floating point values, allowing slight
* variations.
*
* To avoid having to handle this everywhere in the code, some wrapper classes
* exist here to take care of this for you. They will automatically convert
* primitive values to the wrapper class, so you can still use primitive
* constants in your code.
*
* Node that epsilon is currently just set to 10^(-6). We can reduce it or
* adjust it based on type or value later if we see the need. But the class
* should define it, at least by default, to make the interface easy to use as
* most use cases don't really care that much.
*/
#pragma once
#include <iosfwd> // To get std::ostream for output operator
namespace vespalib {
class asciistream;
template<typename Number>
class FloatingPointType {
Number _value;
public:
using Type = FloatingPointType<Number>;
FloatingPointType() : _value(0.0) {}
FloatingPointType(Number n) : _value(n) {}
Number getValue() const { return _value; }
Number abs() const { return (_value < 0 ? -1 * _value : _value); }
bool operator==(Type n) const { return ((*this - n).abs() < 0.000001); }
bool operator!=(Type n) const { return ((*this - n).abs() > 0.000001); }
bool operator<(Type n) const { return (n._value - 0.000001 > _value); }
bool operator>(Type n) const { return (n._value + 0.000001 < _value); }
bool operator<=(Type n) const { return (n._value + 0.000001 > _value); }
bool operator>=(Type n) const { return (n._value - 0.000001 < _value); }
Type operator-(Type n) const { return Type(_value - n._value); }
Type operator+(Type n) const { return Type(_value + n._value); }
Type operator*(Type n) const { return Type(_value * n._value); }
Type operator/(Type n) const { return Type(_value / n._value); }
Type& operator+=(Type n) { _value += n._value; return *this; }
Type& operator-=(Type n) { _value -= n._value; return *this; }
Type& operator*=(Type n) { _value *= n._value; return *this; }
Type& operator/=(Type n) { _value /= n._value; return *this; }
Type& operator++() { ++_value; return *this; }
Type operator++(int) { Type t(_value); ++_value; return t; }
Type& operator--() { --_value; return *this; }
Type operator--(int) { Type t(_value); --_value; return t; }
};
using Double = FloatingPointType<double>;
using Float = FloatingPointType<double>;
template<typename Number>
std::ostream& operator<<(std::ostream& out, FloatingPointType<Number> number);
template<typename Number>
vespalib::asciistream & operator<<(vespalib::asciistream & out, FloatingPointType<Number> number);
} // vespalib
|