Fix sreal::to_int and implement sreal::to_nearest_int
Checks
Commit Message
Fix sreal::to_int and implement sreal::to_nearest_int
while exploring new loop estimate dumps, I noticed that loop iterating 1.8
times by profile is etimated as iterating once instead of 2 by nb_estimate.
While nb_estimate should really be a sreal and I will convert it incrementally,
I found problem is in previous patch doing:
+ *nit = (snit + 0.5).to_int ();
this does not work for sreal because it has only constructor from integer, so
first 0.5 is rounded to 0 and then added to snit.
Some code uses sreal(1, -1) which produces 0.5, but it reuqires unnecessary
addition, so I decided to add to_nearest_int. Testing it I noticed that to_int
is buggy:
(sreal(3)/2).to_int () == 1
while
(sreal(-3)/2).to_int () == -2
Probably not big deal in practice as we do not do conversions on
negative values.
Fix is easy, we need to correctly shift in positive values. This patch fixes
it and adds the to_nearest_int alternative.
Bootstrapped/regtested x86_64-linux, will commit it shortly.
gcc/ChangeLog:
* sreal.cc (sreal::to_nearest_int): New.
(sreal_verify_basics): Verify also to_nearest_int.
(verify_aritmetics): Likewise.
(sreal_verify_conversions): New.
(sreal_cc_tests): Call sreal_verify_conversions.
* sreal.h: (sreal::to_nearest_int): Declare
@@ -116,7 +116,26 @@ sreal::to_int () const
if (m_exp > 0)
return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
if (m_exp < 0)
- return m_sig >> -m_exp;
+ return sign * (SREAL_ABS ((int64_t)m_sig) >> -m_exp);
+ return m_sig;
+}
+
+/* Return nearest integer value of *this. */
+
+int64_t
+sreal::to_nearest_int () const
+{
+ int64_t sign = SREAL_SIGN (m_sig);
+
+ if (m_exp <= -SREAL_BITS)
+ return 0;
+ if (m_exp >= SREAL_PART_BITS)
+ return sign * INTTYPE_MAXIMUM (int64_t);
+ if (m_exp > 0)
+ return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
+ if (m_exp < 0)
+ return sign * ((SREAL_ABS ((int64_t)m_sig) >> -m_exp)
+ + ((SREAL_ABS (m_sig) >> (-m_exp - 1)) & 1));
return m_sig;
}
@@ -286,6 +305,8 @@ sreal_verify_basics (void)
ASSERT_EQ (INT_MIN/2, minimum.to_int ());
ASSERT_EQ (INT_MAX/2, maximum.to_int ());
+ ASSERT_EQ (INT_MIN/2, minimum.to_nearest_int ());
+ ASSERT_EQ (INT_MAX/2, maximum.to_nearest_int ());
ASSERT_FALSE (minus_two < minus_two);
ASSERT_FALSE (seven < seven);
@@ -315,6 +336,10 @@ verify_aritmetics (int64_t a, int64_t b)
ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ());
ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ());
ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ());
+ ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_nearest_int ());
+ ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_nearest_int ());
+ ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_nearest_int ());
+ ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_nearest_int ());
}
/* Verify arithmetics for interesting numbers. */
@@ -377,6 +402,33 @@ sreal_verify_negative_division (void)
ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
}
+static void
+sreal_verify_conversions (void)
+{
+ ASSERT_EQ ((sreal (11) / sreal (3)).to_int (), 3);
+ ASSERT_EQ ((sreal (11) / sreal (3)).to_nearest_int (), 4);
+ ASSERT_EQ ((sreal (10) / sreal (3)).to_int (), 3);
+ ASSERT_EQ ((sreal (10) / sreal (3)).to_nearest_int (), 3);
+ ASSERT_EQ ((sreal (9) / sreal (3)).to_int (), 3);
+ ASSERT_EQ ((sreal (9) / sreal (3)).to_nearest_int (), 3);
+ ASSERT_EQ ((sreal (-11) / sreal (3)).to_int (), -3);
+ ASSERT_EQ ((sreal (-11) / sreal (3)).to_nearest_int (), -4);
+ ASSERT_EQ ((sreal (-10) / sreal (3)).to_int (), -3);
+ ASSERT_EQ ((sreal (-10) / sreal (3)).to_nearest_int (), -3);
+ ASSERT_EQ ((sreal (-3)).to_int (), -3);
+ ASSERT_EQ ((sreal (-3)).to_nearest_int (), -3);
+ for (int i = -100000 ; i < 100000; i += 123)
+ for (int j = -10000 ; j < 100000; j += 71)
+ if (j != 0)
+ {
+ sreal sval = ((sreal)i) / (sreal)j;
+ double val = (double)i / (double)j;
+ ASSERT_EQ ((fabs (sval.to_double () - val) < 0.00001), true);
+ ASSERT_EQ (sval.to_int (), (int)val);
+ ASSERT_EQ (sval.to_nearest_int (), lround (val));
+ }
+}
+
/* Run all of the selftests within this file. */
void sreal_cc_tests ()
@@ -385,6 +437,7 @@ void sreal_cc_tests ()
sreal_verify_arithmetics ();
sreal_verify_shifting ();
sreal_verify_negative_division ();
+ sreal_verify_conversions ();
}
} // namespace selftest
@@ -51,6 +51,7 @@ public:
void dump (FILE *) const;
int64_t to_int () const;
+ int64_t to_nearest_int () const;
double to_double () const;
void stream_out (struct output_block *);
static sreal stream_in (class lto_input_block *);