public Int128(Int128 val) { hi = val.hi; lo = val.lo; }
//------------------------------------------------------------------------------ double Area(OutRec outRec, bool UseFull64BitRange) { OutPt op = outRec.pts; if (UseFull64BitRange) { Int128 a = new Int128(0); do { a += Int128.Int128Mul(op.prev.pt.X, op.pt.Y) - Int128.Int128Mul(op.pt.X, op.prev.pt.Y); op = op.next; } while (op != outRec.pts); return a.ToDouble() / 2; } else { double a = 0; do { a += (op.prev.pt.X * op.pt.Y) - (op.pt.X * op.prev.pt.Y); op = op.next; } while (op != outRec.pts); return a/2; } }
//------------------------------------------------------------------------------ public static double Area(Polygon poly) { int highI = poly.Count - 1; if (highI < 2) return 0; if (FullRangeNeeded(poly)) { Int128 a = new Int128(); a = Int128.Int128Mul(poly[highI].X, poly[0].Y) - Int128.Int128Mul(poly[0].X, poly[highI].Y); for (int i = 0; i < highI; ++i) a += Int128.Int128Mul(poly[i].X, poly[i + 1].Y) - Int128.Int128Mul(poly[i + 1].X, poly[i].Y); return a.ToDouble() / 2; } else { double area = (double)poly[highI].X * (double)poly[0].Y - (double)poly[0].X * (double)poly[highI].Y; for (int i = 0; i < highI; ++i) area += (double)poly[i].X * (double)poly[i + 1].Y - (double)poly[i + 1].X * (double)poly[i].Y; return area / 2; } }
public double ToDouble() { const double shift64 = 18446744073709551616.0; //2^64 const double bit64 = 9223372036854775808.0; if (hi < 0) { Int128 tmp = new Int128(this); tmp = -tmp; if (tmp.lo < 0) return (double)tmp.lo - bit64 - tmp.hi * shift64; else return -(double)tmp.lo - tmp.hi * shift64; } else if (lo < 0) return -(double)lo + bit64 + hi * shift64; else return (double)lo + (double)hi * shift64; }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) throw new ClipperException("Int128: divide by zero"); bool negate = (rhs.hi < 0) != (lhs.hi < 0); Int128 result = new Int128(lhs), denom = new Int128(rhs); if (result.hi < 0) result = -result; if (denom.hi < 0) denom = -denom; if (denom > result) return new Int128(0); //result is only a fraction of 1 denom = -denom; Int128 p = new Int128(0); for (int i = 0; i < 128; ++i) { p.hi = p.hi << 1; if (p.lo < 0) p.hi++; p.lo = (Int64)p.lo << 1; if (result.hi < 0) p.lo++; result.hi = result.hi << 1; if (result.lo < 0) result.hi++; result.lo = (Int64)result.lo << 1; if (p.hi >= 0) { p += denom; result.lo++; } } return negate ? -result : result; }
//nb: Constructing two new Int128 objects every time we want to multiply longs //is slow. So, although calling the Int128Mul method doesn't look as clean, the //code runs significantly faster than if we'd used the * operator. public static Int128 Int128Mul(Int64 lhs, Int64 rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) lhs = -lhs; if (rhs < 0) rhs = -rhs; UInt64 int1Hi = (UInt64)lhs >> 32; UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF; UInt64 int2Hi = (UInt64)rhs >> 32; UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF; //nb: see comments in clipper.pas UInt64 a = int1Hi * int2Hi; UInt64 b = int1Lo * int2Lo; UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi; Int64 lo, hi; hi = (Int64)(a + (c >> 32)); lo = (Int64)(c << 32); lo += (Int64)b; if ((UInt64)lo < b) hi++; var result = new Int128(lo, hi); return negate ? -result : result; }