mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 16:24:57 +01:00
temporal: alternative solution to overflow in timeline operator*()
This uses boost::multiprecision::int512_t when multiplying and dividing by the numerator and denominator of a ratio_t. 128 bits would be sufficient but for some reason, the boost docs show the 512 bit variant being very slightly faster. This is a better solution than using a double, which although it will prevent overflow has fairly limited resolution.
This commit is contained in:
parent
540a15efa0
commit
60e5b84d78
2 changed files with 36 additions and 5 deletions
|
|
@ -359,9 +359,8 @@ ControlList::list_merge (ControlList const& other, boost::function<double(double
|
||||||
void
|
void
|
||||||
ControlList::_x_scale (ratio_t const & factor)
|
ControlList::_x_scale (ratio_t const & factor)
|
||||||
{
|
{
|
||||||
double double_factor = (double)factor;
|
|
||||||
for (iterator i = _events.begin(); i != _events.end(); ++i) {
|
for (iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
(*i)->when = timepos_t::from_superclock ((*i)->when.val() * double_factor + 0.5);
|
(*i)->when = (*i)->when.operator* (factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty ();
|
mark_dirty ();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
|
|
||||||
#include "pbd/enumwriter.h"
|
#include "pbd/enumwriter.h"
|
||||||
#include "pbd/error.h"
|
#include "pbd/error.h"
|
||||||
#include "pbd/compose.h"
|
#include "pbd/compose.h"
|
||||||
|
|
@ -200,8 +202,23 @@ timecnt_t::compute_beats() const
|
||||||
timecnt_t
|
timecnt_t
|
||||||
timecnt_t::operator*(ratio_t const & r) const
|
timecnt_t::operator*(ratio_t const & r) const
|
||||||
{
|
{
|
||||||
const int62_t v (_distance.flagged(), int_div_round (_distance.val() * r.numerator(), r.denominator()));
|
boost::multiprecision::int512_t bignum = _distance.val();
|
||||||
return timecnt_t (v, _position);
|
|
||||||
|
bignum *= r.numerator ();
|
||||||
|
bignum /= r.denominator ();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
int64_t midnum = bignum.convert_to<int64_t> ();
|
||||||
|
assert (midnum < int62_t::max);
|
||||||
|
const int62_t v (_distance.flagged(), midnum);
|
||||||
|
return timecnt_t (v, _position);
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
fatal << X_("arithmetic overflow in timeline math\n") << endmsg;
|
||||||
|
/* NOTREACHED */
|
||||||
|
return timecnt_t ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ratio_t
|
ratio_t
|
||||||
|
|
@ -589,7 +606,22 @@ timepos_t
|
||||||
timepos_t::operator*(ratio_t const & n) const
|
timepos_t::operator*(ratio_t const & n) const
|
||||||
{
|
{
|
||||||
/* this cannot make the value negative, since ratio_t is always positive */
|
/* this cannot make the value negative, since ratio_t is always positive */
|
||||||
return timepos_t (is_beats(), int_div_round (val() * n.numerator(), n.denominator()));
|
boost::multiprecision::int512_t bignum = val();
|
||||||
|
|
||||||
|
bignum *= n.numerator ();
|
||||||
|
bignum /= n.denominator ();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
int64_t midnum = bignum.convert_to<int64_t> ();
|
||||||
|
assert (midnum < int62_t::max);
|
||||||
|
return timepos_t (is_beats(), midnum);
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
fatal << X_("arithmetic overflow in timepos_t::operator* (ratio_t)\n") << endmsg;
|
||||||
|
/* NOTREACHED */
|
||||||
|
return timepos_t();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timepos_t &
|
timepos_t &
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue