Esempio n. 1
0
template<int m> static inline Vector<ExactInt,m> to_exact(const Vector<Quantized,m>& x) {
  Vector<ExactInt,m> r;
  for (int i=0;i<m;i++) {
    r[i] = ExactInt(x[i]);
    assert(r[i]==x[i]); // Make sure the input is actually quantized
  }
  return r;
}
Esempio n. 2
0
// Our fixed deterministic pseudorandom perturbation sequence.  We limit ourselves to 32 bits so that we can pull four values out of a uint128_t.
template<int m> inline Vector<ExactInt,m> perturbation(const int level, const int i) {
  static_assert(m<=4,"");
  const int bits = min(exact::log_bound+1,128/4);
  const auto limit = ExactInt(1)<<(bits-1);
  const uint128_t noise = threefry(level,i);
  Vector<ExactInt,m> result;
  for (int a=0;a<m;a++)
    result[a] = (cast_uint128<ExactInt>(noise>>32*a)&(2*limit-1))-limit;
  return result;
}
Esempio n. 3
0
static void predicate_tests() {
  IntervalScope scope;
  typedef Vector<double,2> TV2;
  typedef Vector<Quantized,2> QV2;

  // Compare triangle_oriented and incircle against approximate floating point versions
  struct F {
    static inline double triangle_oriented(const TV2 p0, const TV2 p1, const TV2 p2) {
      return edet(p1-p0,p2-p0);
    };
    static inline double incircle(const TV2 p0, const TV2 p1, const TV2 p2, const TV2 p3) {
      const auto d0 = p0-p3, d1 = p1-p3, d2 = p2-p3;
      return edet(ROW(d0),ROW(d1),ROW(d2));
    }
  };
  const auto random = new_<Random>(9817241);
  for (int step=0;step<100;step++) {
    #define MAKE(i) \
      const auto p##i = tuple(i,QV2(random->uniform<Vector<ExactInt,2>>(-exact::bound,exact::bound))); \
      const TV2 x##i(p##i.y);
    MAKE(0) MAKE(1) MAKE(2) MAKE(3)
    GEODE_ASSERT(triangle_oriented(p0,p1,p2)==(F::triangle_oriented(x0,x1,x2)>0));
    GEODE_ASSERT(incircle(p0,p1,p2,p3)==(F::incircle(x0,x1,x2,x3)>0));
  }

  // Test behavior for large numbers, using the scale invariance and antisymmetry of incircle.
  for (const int i : range(exact::log_bound)) {
    const auto bound = ExactInt(1)<<i;
    const auto p0 = tuple(0,QV2(-bound,-bound)), // Four points on a circle of radius sqrt(2)*bound
               p1 = tuple(1,QV2( bound,-bound)),
               p2 = tuple(2,QV2( bound, bound)),
               p3 = tuple(3,QV2(-bound, bound));
    GEODE_ASSERT(!incircle(p0,p1,p2,p3));
    GEODE_ASSERT( incircle(p0,p1,p3,p2));
  }
}
Esempio n. 4
0
// Cast num/den to an int, rounding towards nearest.  All inputs are destroyed.  Take a sqrt if desired.
// The values array must consist of r numerators followed by one denominator.
void snap_divs(RawArray<Quantized> result, RawArray<mp_limb_t,2> values, const bool take_sqrt) {
  assert(result.size()+1==values.m);

  // For division, we seek x s.t.
  //   x-1/2 <= num/den <= x+1/2
  //   2x-1 <= 2num/den <= 2x+1
  //   2x-1 <= floor(2num/den) <= 2x+1
  //   2x <= 1+floor(2num/den) <= 2x+2
  //   x <= (1+floor(2num/den))//2 <= x+1
  //   x = (1+floor(2num/den))//2

  // In the sqrt case, we seek a nonnegative integer x s.t.
  //   x-1/2 <= sqrt(num/den) < x+1/2
  //   2x-1 <= sqrt(4num/den) < 2x+1
  // Now the leftmost and rightmost expressions are integral, so we can take floors to get
  //   2x-1 <= floor(sqrt(4num/den)) < 2x+1
  // Since sqrt is monotonic and maps integers to integers, floor(sqrt(floor(x))) = floor(sqrt(x)), so
  //   2x-1 <= floor(sqrt(floor(4num/den))) < 2x+1
  //   2x <= 1+floor(sqrt(floor(4num/den))) < 2x+2
  //   x <= (1+floor(sqrt(floor(4num/den))))//2 < x+1
  //   x = (1+floor(sqrt(floor(4num/den))))//2

  // Thus, both cases look like
  //   x = (1+f(2**k*num/den))//2
  // where k = 1 or 2 and f is some truncating integer op (division or division+sqrt).

  // Adjust denominator to be positive
  const auto raw_den = values[result.size()];
  const bool den_negative = mp_limb_signed_t(raw_den.back())<0;
  if (den_negative)
    mpn_neg(raw_den.data(),raw_den.data(),raw_den.size());
  const auto den = trim(raw_den);
  assert(den.size()); // Zero should be prevented by the caller

  // Prepare for divisions
  const auto q = GEODE_RAW_ALLOCA(values.n-den.size()+1,mp_limb_t),
             r = GEODE_RAW_ALLOCA(den.size(),mp_limb_t);

  // Compute each component of the result
  for (int i=0;i<result.size();i++) {
    // Adjust numerator to be positive
    const auto num = values[i];
    const bool num_negative = mp_limb_signed_t(num.back())<0;
    if (take_sqrt && num_negative!=den_negative && !num.contains_only(0))
      throw RuntimeError("perturbed_ratio: negative value in square root");
    if (num_negative)
      mpn_neg(num.data(),num.data(),num.size());

    // Add enough bits to allow round-to-nearest computation after performing truncating operations
    mpn_lshift(num.data(),num.data(),num.size(),take_sqrt?2:1);
    // Perform division
    mpn_tdiv_qr(q.data(),r.data(),0,num.data(),num.size(),den.data(),den.size());
    const auto trim_q = trim(q);
    if (!trim_q.size()) {
      result[i] = 0;
      continue;
    }
    // Take sqrt if desired, reusing the num buffer
    const auto s = take_sqrt ? sqrt_helper(num,trim_q) : trim_q;

    // Verify that result lies in [-exact::bound,exact::bound];
    const int ratio = sizeof(ExactInt)/sizeof(mp_limb_t);
    static_assert(ratio<=2,"");
    if (s.size() > ratio)
      goto overflow;
    const auto nn = ratio==2 && s.size()==2 ? s[0]|ExactInt(s[1])<<8*sizeof(mp_limb_t) : s[0],
               n = (1+nn)/2;
    if (uint64_t(n) > uint64_t(exact::bound))
      goto overflow;

    // Done!
    result[i] = (num_negative==den_negative?1:-1)*Quantized(n);
  }

  return;
  overflow:
  throw OverflowError("perturbed_ratio: overflow in l'Hopital expansion");
}