# Thread: Library for working with error terms?

1. ## Library for working with error terms?

Take the number V = 1.2 +/- 0.3 for example. So V spans the interval [0.9, 1.5]. Then V + V -> 2.4 +/- 0.6 -> [1.8, 3] and V * V = 1.53 +/- 0.72 -> [0.81, 2.25], etc.

I have a rough implementation working already (only supports +, -, *, and / at this point) but really I would rather not have to code this up by hand. Any suggestions for an existing library? 2. 3. Originally Posted by john.c Thanks! I didn't see any single-header C++ libraries on the list but that does seem to be the search term I was looking for.

Also regarding the rules of operator overloading. Should they all be moved outside the class or not?

Code:
```template <typename T>
class roughly
{
public:

T average, extrema;

roughly(const T& average = 0, const T& extrema = 0)
{
set(average, extrema);
}

roughly(const roughly& rhs)
{
set(rhs.average, rhs.extrema);
}

roughly& set(const T& average, const T& extrema = 0)
{
roughly& that = *this;
that.average = average;
that.extrema = extrema < 0 ? -extrema : extrema;
return that;
}

T low() const
{
return average - extrema;
}

T high() const
{
return average + extrema;
}

roughly& operator += (const roughly& rhs)
{
average += rhs.average;
extrema += rhs.extrema;
return *this;
}

roughly& operator -= (const roughly& rhs)
{
average -= rhs.average;
extrema -= rhs.extrema;
return *this;
}

roughly& meld(const T& lows, const T& highs)
{
average = (lows + highs) / 2;
extrema = average - lows;
return *this;
}

roughly& operator *= (const roughly& rhs)
{
return meld(low() * rhs.low(), high() * rhs.high());
}

roughly& operator /= (const roughly& rhs)
{
auto rl = rhs.low();
auto lows = rl ? low() / rl : 0;
auto rh = rhs.high();
auto highs = rh ? high() / rh : 0;
return meld(lows, highs);
}
};

template <typename T>
roughly<T>
inline operator +
(
const roughly<T>& lhs,
const roughly<T>& rhs
)
{
return roughly<T>(lhs) += rhs;
}

template <typename T>
roughly<T>
inline operator -
(
const roughly<T>& lhs,
const roughly<T>& rhs
)
{
return roughly<T>(lhs) -= rhs;
}

template <typename T>
roughly<T>
inline operator *
(
const roughly<T>& lhs,
const roughly<T>& rhs
)
{
return roughly<T>(lhs) *= rhs;
}

template <typename T>
roughly<T>
inline operator /
(
const roughly<T>& lhs,
const roughly<T>& rhs
)
{
return roughly<T>(lhs) /= rhs;
}

template <typename S, typename T>
S&
operator <<
(
S& stream,
const roughly<T>& data
)
{
return stream << data.average
<< " [+/-] " << data.extrema;
}``` 4. Originally Posted by Sir Galahad Thanks! I didn't see any single-header C++ libraries on the list but that does seem to be the search term I was looking for.
I used my googlefu and typed in "programming library measurement error". Originally Posted by Sir Galahad Also regarding the rules of operator overloading. Should they all be moved outside the class or not?
That's definitely a laserlight question (she's a C++ expert). However, what you have looks pretty good to me, with the += (and others like that) in the class and the + and others outside. 5. Originally Posted by Sir Galahad
Also regarding the rules of operator overloading. Should they all be moved outside the class or not?
It's the same rule as any other function: if it needs (or may be critical for efficiency for it to have) access to the internals of the class, then it should be a member or a friend. Otherwise, if it can be (efficiently) implemented without being a member or a friend, then it should be a non-member non-friend.

Looking over your code, I might suggest (untested even for compile errors):
Code:
```template <typename T>
class roughly
{
public:
roughly(const T& average = T(), const T& extrema = T()) :
average(average), extrema(extrema < T() ? -extrema : extrema) {}

T getAverage() const
{
return average;
}

T getExtrema() const
{
return extrema;
}

roughly& operator += (const roughly& rhs)
{
average += rhs.average;
extrema += rhs.extrema;
return *this;
}

roughly& operator -= (const roughly& rhs)
{
average -= rhs.average;
extrema -= rhs.extrema;
return *this;
}

roughly& operator *= (const roughly& rhs)
{
return meld(low() * rhs.low(), high() * rhs.high());
}

roughly& operator /= (const roughly& rhs)
{
auto rl = rhs.low();
auto lows = rl ? low() / rl : T();
auto rh = rhs.high();
auto highs = rh ? high() / rh : T();
return meld(lows, highs);
}
private:
T average, extrema;

T low() const
{
return average - extrema;
}

T high() const
{
return average + extrema;
}

roughly& meld(const T& lows, const T& highs)
{
average = (lows + highs) / T(2);
extrema = average - lows;
return *this;
}
};

template <typename T>
inline
roughly<T> operator + (const roughly<T>& lhs, const roughly<T>& rhs)
{
return roughly<T>(lhs) += rhs;
}

template <typename T>
inline
roughly<T> operator - (const roughly<T>& lhs, const roughly<T>& rhs)
{
return roughly<T>(lhs) -= rhs;
}

template <typename T>
inline
roughly<T> operator * (const roughly<T>& lhs, const roughly<T>& rhs)
{
return roughly<T>(lhs) *= rhs;
}

template <typename T>
inline
roughly<T> operator / (const roughly<T>& lhs, const roughly<T>& rhs)
{
return roughly<T>(lhs) /= rhs;
}

template <typename T>
inline
std::ostream& operator << (std::ostream& stream, const roughly<T>& data)
{
return stream << data.getAverage() << " [+/-] " << data.getExtrema();
}```
My reasoning:
• You want to control extrema to be non-negative, so it makes sense to make it private and control how it is set.
• You might as well make use of the constructor initialiser list.
• Using T() should give the zero value of type T even for say, a custom bignum class.
• The implicit copy constructor will do the job efficiently, so there's no need to define it such that it does the extrema check that would have already been done.
• It looks like low, high, and meld are helper functions, so I have moved them to have private access.
• I have used T(2) instead of 2 similiarly to get the number 2 of type T. It might not be important, but then if there's say, a bignum class that doesn't support implicit conversions from int, this could turn out to be a boon.
• I have neither a C++ compiler nor my copy of the C++ standard right now to check, but I believe that if you want to explicitly declare a function template as inline, then the inline keyword comes between the template parameter declarations and the return type.
• It looks like the operator<< overload is intended for output streams, so rather than having a template parameter S, it makes more sense to explicitly overload for ostream. This could help avoid confusion with say, a future overload of operator<< to perform left shifting. 6. @laserlight, I checked it and it compiles just fine.
And moving the inline keyword to the original position causes an error. 7. Originally Posted by laserlight It's the same rule as any other function: if it needs (or may be critical for efficiency for it to have) access to the internals of the class, then it should be a member or a friend. Otherwise, if it can be (efficiently) implemented without being a member or a friend, then it should be a non-member non-friend.

Looking over your code, I might suggest (untested even for compile errors):
Code:
`...`
My reasoning:
• You want to control extrema to be non-negative, so it makes sense to make it private and control how it is set.
• You might as well make use of the constructor initialiser list.
• Using T() should give the zero value of type T even for say, a custom bignum class.
• The implicit copy constructor will do the job efficiently, so there's no need to define it such that it does the extrema check that would have already been done.
• It looks like low, high, and meld are helper functions, so I have moved them to have private access.
• I have used T(2) instead of 2 similiarly to get the number 2 of type T. It might not be important, but then if there's say, a bignum class that doesn't support implicit conversions from int, this could turn out to be a boon.
• I have neither a C++ compiler nor my copy of the C++ standard right now to check, but I believe that if you want to explicitly declare a function template as inline, then the inline keyword comes between the template parameter declarations and the return type.
• It looks like the operator<< overload is intended for output streams, so rather than having a template parameter S, it makes more sense to explicitly overload for ostream. This could help avoid confusion with say, a future overload of operator<< to perform left shifting.
I was just thinking that I'd heard that operators defined outside of the class were somehow "more flexible" or something?

Thanks for the other bits of advice by the way. I think I might need a refresher course on this stuff! 8. Originally Posted by Sir Galahad
I was just thinking that I'd heard that operators defined outside of the class were somehow "more flexible" or something?
You're probably thinking of how an implicit conversion could work with say, operator+

If you have operator+ as a member, then you could write x * 2 but not 2 * x. As a non-member, you could write both. But this is not so for operator+= as you want x += 2, but 2 += x wouldn't make the same sense. 9. Originally Posted by laserlight You're probably thinking of how an implicit conversion could work with say, operator+

If you have operator+ as a member, then you could write x * 2 but not 2 * x. As a non-member, you could write both. But this is not so for operator+= as you want x += 2, but 2 += x wouldn't make the same sense.
Yes, that's it! That's exactly what I was talking about. Okay, so is a friend function the same thing or is there some semantic difference? I'll look it up... 10. A friend function is just a non-member function that has access to private members as if it were a member function. 11. Originally Posted by laserlight A friend function is just a non-member function that has access to private members as if it were a member function.
Perfect. And defining them as friend functions means less verbose template syntax too, so I guess I'll do it that way. 12. No, member functions defined in a template class definition tends to be less verbose: you don't need to keep listing the template parameters.

Why do you need friend functions here? 13. Originally Posted by laserlight No, member functions defined in a template class definition tends to be less verbose: you don't need to keep listing the template parameters.

Why do you need friend functions here?
I honestly don't know what I was thinking there. Yeah that would not work. Popular pages Recent additions #### Tags for this Thread

implementation, library, point, supports, working 