/* Your code here */ /* cairo - a vector graphics library with display and print output * * Copyright © 2004 Keith Packard * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is Keith Packard * * Contributor(s): * Keith R. Packard */ /* Keep these headers */ #include #include #include #include /* Standard headers - it's recommended to leave them included */ #include #include "config.h" #include "int64.h" #include "tools.h" int32_t int64_trunc_int32(int64_t val) { int32_t nval; int64_t tmp = val; uint8_t s=0; if(int64_negative(tmp)) { tmp=int64_negate(tmp); s=1; } nval=tmp.lo; if(s) nval=-nval; return nval; } uint64_t uint32_to_uint64 (uint32_t i) { uint64_t q; q.lo = i; q.hi = 0; return q; } int64_t int32_to_int64 (int32_t i) { uint64_t q; q.lo = i; q.hi = i < 0 ? -1 : 0; return q; } static const uint64_t uint32s_to_uint64 (uint32_t h, uint32_t l) { uint64_t q; q.lo = l; q.hi = h; return q; } uint64_t uint64_add (uint64_t a, uint64_t b) { uint64_t s; s.hi = a.hi + b.hi; s.lo = a.lo + b.lo; if (s.lo < a.lo) s.hi++; return s; } uint64_t uint64_sub (uint64_t a, uint64_t b) { uint64_t s; s.hi = a.hi - b.hi; s.lo = a.lo - b.lo; if (s.lo > a.lo) s.hi--; return s; } #define uint32_lo(i) ((i) & 0xffff) #define uint32_hi(i) ((i) >> 16) #define uint32_carry16 ((1) << 16) uint64_t uint32x32_64_mul (uint32_t a, uint32_t b) { uint64_t s; uint16_t ah, al, bh, bl; uint32_t r0, r1, r2, r3; al = uint32_lo (a); ah = uint32_hi (a); bl = uint32_lo (b); bh = uint32_hi (b); r0 = (uint32_t) al * bl; r1 = (uint32_t) al * bh; r2 = (uint32_t) ah * bl; r3 = (uint32_t) ah * bh; r1 += uint32_hi(r0); /* no carry possible */ r1 += r2; /* but this can carry */ if (r1 < r2) /* check */ r3 += uint32_carry16; s.hi = r3 + uint32_hi(r1); s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0); return s; } int64_t int32x32_64_mul (int32_t a, int32_t b) { int64_t s; s = uint32x32_64_mul ((uint32_t) a, (uint32_t) b); if (a < 0) s.hi -= b; if (b < 0) s.hi -= a; return s; } uint64_t uint64_mul (uint64_t a, uint64_t b) { uint64_t s; s = uint32x32_64_mul (a.lo, b.lo); s.hi += a.lo * b.hi + a.hi * b.lo; return s; } uint64_t uint64_lsl (uint64_t a, int shift) { if (shift >= 32) { a.hi = a.lo; a.lo = 0; shift -= 32; } if (shift) { a.hi = a.hi << shift | a.lo >> (32 - shift); a.lo = a.lo << shift; } return a; } uint64_t uint64_rsl (uint64_t a, int shift) { if (shift >= 32) { a.lo = a.hi; a.hi = 0; shift -= 32; } if (shift) { a.lo = a.lo >> shift | a.hi << (32 - shift); a.hi = a.hi >> shift; } return a; } #define uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n))) int64_t uint64_rsa (int64_t a, int shift) { if (shift >= 32) { a.lo = a.hi; a.hi = uint32_rsa (a.hi, 31); shift -= 32; } if (shift) { a.lo = a.lo >> shift | a.hi << (32 - shift); a.hi = uint32_rsa (a.hi, shift); } return a; } int uint64_lt (uint64_t a, uint64_t b) { return (a.hi < b.hi || (a.hi == b.hi && a.lo < b.lo)); } int uint64_eq (uint64_t a, uint64_t b) { return a.hi == b.hi && a.lo == b.lo; } int int64_lt (int64_t a, int64_t b) { if (int64_negative (a) && !int64_negative (b)) return 1; if (!int64_negative (a) && int64_negative (b)) return 0; return uint64_lt (a, b); } int64_t int64_negate (int64_t a) { a.lo = ~a.lo; a.hi = ~a.hi; if (++a.lo == 0) ++a.hi; return a; } uquorem64_t uint64_divrem (uint64_t num, uint64_t den) { uquorem64_t qr; uint64_t bit; uint64_t quo; bit = uint32_to_uint64 (1); /* normalize to make den >= num, but not overflow */ while (uint64_lt (den, num) && (den.hi & 0x80000000) == 0) { bit = uint64_lsl (bit, 1); den = uint64_lsl (den, 1); } quo = uint32_to_uint64 (0); /* generate quotient, one bit at a time */ while (bit.hi | bit.lo) { if (uint64_le (den, num)) { num = uint64_sub (num, den); quo = uint64_add (quo, bit); } bit = uint64_rsl (bit, 1); den = uint64_rsl (den, 1); } qr.quo = quo; qr.rem = num; return qr; } quorem64_t int64_divrem (int64_t num, int64_t den) { int num_neg = int64_negative (num); int den_neg = int64_negative (den); uquorem64_t uqr; quorem64_t qr; if (num_neg) num = int64_negate (num); if (den_neg) den = int64_negate (den); uqr = uint64_divrem (num, den); if (num_neg) qr.rem = int64_negate (uqr.rem); else qr.rem = uqr.rem; if (num_neg != den_neg) qr.quo = int64_negate (uqr.quo); else qr.quo = uqr.quo; return qr; } #ifdef DEBUG char text64buffer[21] = {0}; // Unsigned int to string (s), which also returns the pointer to the string char* ui64toa(uint64_t n, uint8_t zeropad_len) { uint8_t i = 0; uint64_t zero64 = uint32_to_uint64(0); uint64_t ten64 = uint32_to_uint64(10); do { /* generate digits in reverse order */ text64buffer[i++] = uint64_divrem(n,ten64).rem.lo + '0'; /* get next digit */ n=uint64_divrem(n,ten64).quo; } while (uint64_gt(n,zero64)); /* delete it */ for(; i