13ff48bf5SDavid du Colombier /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gsmisc.c,v 1.22 2004/12/08 21:35:13 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Miscellaneous utilities for Ghostscript library */
193ff48bf5SDavid du Colombier
203ff48bf5SDavid du Colombier /*
213ff48bf5SDavid du Colombier * In order to capture the original definition of sqrt, which might be
223ff48bf5SDavid du Colombier * either a procedure or a macro and might not have an ANSI-compliant
233ff48bf5SDavid du Colombier * prototype (!), we need to do the following:
243ff48bf5SDavid du Colombier */
253ff48bf5SDavid du Colombier #include "std.h"
263ff48bf5SDavid du Colombier #if defined(VMS) && defined(__GNUC__)
273ff48bf5SDavid du Colombier /* DEC VAX/VMS C comes with a math.h file, but GNU VAX/VMS C does not. */
283ff48bf5SDavid du Colombier # include "vmsmath.h"
293ff48bf5SDavid du Colombier #else
303ff48bf5SDavid du Colombier # include <math.h>
313ff48bf5SDavid du Colombier #endif
323ff48bf5SDavid du Colombier inline private double
orig_sqrt(double x)333ff48bf5SDavid du Colombier orig_sqrt(double x)
343ff48bf5SDavid du Colombier {
353ff48bf5SDavid du Colombier return sqrt(x);
363ff48bf5SDavid du Colombier }
373ff48bf5SDavid du Colombier
383ff48bf5SDavid du Colombier /* Here is the real #include section. */
397dd7cddfSDavid du Colombier #include "ctype_.h"
407dd7cddfSDavid du Colombier #include "malloc_.h"
417dd7cddfSDavid du Colombier #include "math_.h"
427dd7cddfSDavid du Colombier #include "memory_.h"
437dd7cddfSDavid du Colombier #include "string_.h"
447dd7cddfSDavid du Colombier #include "gx.h"
457dd7cddfSDavid du Colombier #include "gpcheck.h" /* for gs_return_check_interrupt */
467dd7cddfSDavid du Colombier #include "gserror.h" /* for prototype */
477dd7cddfSDavid du Colombier #include "gserrors.h"
487dd7cddfSDavid du Colombier #include "gconfigv.h" /* for USE_ASM */
497dd7cddfSDavid du Colombier #include "gxfarith.h"
507dd7cddfSDavid du Colombier #include "gxfixed.h"
517dd7cddfSDavid du Colombier
523ff48bf5SDavid du Colombier /* ------ Redirected stdout and stderr ------ */
533ff48bf5SDavid du Colombier
543ff48bf5SDavid du Colombier #include <stdarg.h>
553ff48bf5SDavid du Colombier #define PRINTF_BUF_LENGTH 1024
563ff48bf5SDavid du Colombier
outprintf(const gs_memory_t * mem,const char * fmt,...)57*593dc095SDavid du Colombier int outprintf(const gs_memory_t *mem, const char *fmt, ...)
583ff48bf5SDavid du Colombier {
593ff48bf5SDavid du Colombier int count;
603ff48bf5SDavid du Colombier char buf[PRINTF_BUF_LENGTH];
613ff48bf5SDavid du Colombier va_list args;
623ff48bf5SDavid du Colombier
633ff48bf5SDavid du Colombier va_start(args, fmt);
643ff48bf5SDavid du Colombier
653ff48bf5SDavid du Colombier count = vsprintf(buf, fmt, args);
66*593dc095SDavid du Colombier outwrite(mem, buf, count);
673ff48bf5SDavid du Colombier if (count >= PRINTF_BUF_LENGTH) {
683ff48bf5SDavid du Colombier count = sprintf(buf,
693ff48bf5SDavid du Colombier "PANIC: printf exceeded %d bytes. Stack has been corrupted.\n",
703ff48bf5SDavid du Colombier PRINTF_BUF_LENGTH);
71*593dc095SDavid du Colombier outwrite(mem, buf, count);
723ff48bf5SDavid du Colombier }
733ff48bf5SDavid du Colombier va_end(args);
743ff48bf5SDavid du Colombier return count;
753ff48bf5SDavid du Colombier }
763ff48bf5SDavid du Colombier
errprintf(const char * fmt,...)773ff48bf5SDavid du Colombier int errprintf(const char *fmt, ...)
783ff48bf5SDavid du Colombier {
793ff48bf5SDavid du Colombier int count;
803ff48bf5SDavid du Colombier char buf[PRINTF_BUF_LENGTH];
813ff48bf5SDavid du Colombier va_list args;
823ff48bf5SDavid du Colombier
833ff48bf5SDavid du Colombier va_start(args, fmt);
843ff48bf5SDavid du Colombier
853ff48bf5SDavid du Colombier count = vsprintf(buf, fmt, args);
863ff48bf5SDavid du Colombier errwrite(buf, count);
873ff48bf5SDavid du Colombier if (count >= PRINTF_BUF_LENGTH) {
883ff48bf5SDavid du Colombier count = sprintf(buf,
893ff48bf5SDavid du Colombier "PANIC: printf exceeded %d bytes. Stack has been corrupted.\n",
903ff48bf5SDavid du Colombier PRINTF_BUF_LENGTH);
913ff48bf5SDavid du Colombier errwrite(buf, count);
923ff48bf5SDavid du Colombier }
933ff48bf5SDavid du Colombier va_end(args);
943ff48bf5SDavid du Colombier return count;
953ff48bf5SDavid du Colombier }
963ff48bf5SDavid du Colombier
977dd7cddfSDavid du Colombier /* ------ Debugging ------ */
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier /* Ghostscript writes debugging output to gs_debug_out. */
1007dd7cddfSDavid du Colombier /* We define gs_debug and gs_debug_out even if DEBUG isn't defined, */
1017dd7cddfSDavid du Colombier /* so that we can compile individual modules with DEBUG set. */
1027dd7cddfSDavid du Colombier char gs_debug[128];
1037dd7cddfSDavid du Colombier FILE *gs_debug_out;
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier /* Test whether a given debugging option is selected. */
1067dd7cddfSDavid du Colombier /* Upper-case letters automatically include their lower-case counterpart. */
1077dd7cddfSDavid du Colombier bool
gs_debug_c(int c)1087dd7cddfSDavid du Colombier gs_debug_c(int c)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier return
1117dd7cddfSDavid du Colombier (c >= 'a' && c <= 'z' ? gs_debug[c] | gs_debug[c ^ 32] : gs_debug[c]);
1127dd7cddfSDavid du Colombier }
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier /* Define the formats for debugging printout. */
1157dd7cddfSDavid du Colombier const char *const dprintf_file_and_line_format = "%10s(%4d): ";
1167dd7cddfSDavid du Colombier const char *const dprintf_file_only_format = "%10s(unkn): ";
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier /*
1197dd7cddfSDavid du Colombier * Define the trace printout procedures. We always include these, in case
1203ff48bf5SDavid du Colombier * other modules were compiled with DEBUG set. Note that they must use
1213ff48bf5SDavid du Colombier * out/errprintf, not fprintf nor fput[cs], because of the way that
1223ff48bf5SDavid du Colombier * stdout/stderr are implemented on DLL/shared library builds.
1237dd7cddfSDavid du Colombier */
1243ff48bf5SDavid du Colombier void
dflush(void)1253ff48bf5SDavid du Colombier dflush(void)
1263ff48bf5SDavid du Colombier {
1273ff48bf5SDavid du Colombier errflush();
1283ff48bf5SDavid du Colombier }
1297dd7cddfSDavid du Colombier private const char *
dprintf_file_tail(const char * file)1307dd7cddfSDavid du Colombier dprintf_file_tail(const char *file)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier const char *tail = file + strlen(file);
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier while (tail > file &&
1357dd7cddfSDavid du Colombier (isalnum(tail[-1]) || tail[-1] == '.' || tail[-1] == '_')
1367dd7cddfSDavid du Colombier )
1377dd7cddfSDavid du Colombier --tail;
1387dd7cddfSDavid du Colombier return tail;
1397dd7cddfSDavid du Colombier }
1407dd7cddfSDavid du Colombier #if __LINE__ /* compiler provides it */
1417dd7cddfSDavid du Colombier void
dprintf_file_and_line(const char * file,int line)1423ff48bf5SDavid du Colombier dprintf_file_and_line(const char *file, int line)
1437dd7cddfSDavid du Colombier {
1447dd7cddfSDavid du Colombier if (gs_debug['/'])
1453ff48bf5SDavid du Colombier dpf(dprintf_file_and_line_format,
1467dd7cddfSDavid du Colombier dprintf_file_tail(file), line);
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier #else
1497dd7cddfSDavid du Colombier void
dprintf_file_only(const char * file)1503ff48bf5SDavid du Colombier dprintf_file_only(const char *file)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier if (gs_debug['/'])
1533ff48bf5SDavid du Colombier dpf(dprintf_file_only_format, dprintf_file_tail(file));
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier #endif
1567dd7cddfSDavid du Colombier void
printf_program_ident(const gs_memory_t * mem,const char * program_name,long revision_number)157*593dc095SDavid du Colombier printf_program_ident(const gs_memory_t *mem, const char *program_name, long revision_number)
1587dd7cddfSDavid du Colombier {
1593ff48bf5SDavid du Colombier if (program_name)
160*593dc095SDavid du Colombier outprintf(mem, (revision_number ? "%s " : "%s"), program_name);
1617dd7cddfSDavid du Colombier if (revision_number) {
1627dd7cddfSDavid du Colombier int fpart = revision_number % 100;
1637dd7cddfSDavid du Colombier
164*593dc095SDavid du Colombier outprintf(mem, "%d.%02d", (int)(revision_number / 100), fpart);
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier void
eprintf_program_ident(const char * program_name,long revision_number)1683ff48bf5SDavid du Colombier eprintf_program_ident(const char *program_name,
1697dd7cddfSDavid du Colombier long revision_number)
1707dd7cddfSDavid du Colombier {
1717dd7cddfSDavid du Colombier if (program_name) {
1723ff48bf5SDavid du Colombier epf((revision_number ? "%s " : "%s"), program_name);
1733ff48bf5SDavid du Colombier if (revision_number) {
1743ff48bf5SDavid du Colombier int fpart = revision_number % 100;
1753ff48bf5SDavid du Colombier
1763ff48bf5SDavid du Colombier epf("%d.%02d", (int)(revision_number / 100), fpart);
1773ff48bf5SDavid du Colombier }
1783ff48bf5SDavid du Colombier epf(": ");
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier #if __LINE__ /* compiler provides it */
1827dd7cddfSDavid du Colombier void
lprintf_file_and_line(const char * file,int line)1833ff48bf5SDavid du Colombier lprintf_file_and_line(const char *file, int line)
1847dd7cddfSDavid du Colombier {
1853ff48bf5SDavid du Colombier epf("%s(%d): ", file, line);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier #else
1887dd7cddfSDavid du Colombier void
lprintf_file_only(FILE * f,const char * file)1897dd7cddfSDavid du Colombier lprintf_file_only(FILE * f, const char *file)
1907dd7cddfSDavid du Colombier {
1913ff48bf5SDavid du Colombier epf("%s(?): ", file);
1927dd7cddfSDavid du Colombier }
1937dd7cddfSDavid du Colombier #endif
1947dd7cddfSDavid du Colombier
1957dd7cddfSDavid du Colombier /* Log an error return. We always include this, in case other */
1967dd7cddfSDavid du Colombier /* modules were compiled with DEBUG set. */
1977dd7cddfSDavid du Colombier #undef gs_log_error /* in case DEBUG isn't set */
1987dd7cddfSDavid du Colombier int
gs_log_error(int err,const char * file,int line)1997dd7cddfSDavid du Colombier gs_log_error(int err, const char *file, int line)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier if (gs_log_errors) {
2027dd7cddfSDavid du Colombier if (file == NULL)
2037dd7cddfSDavid du Colombier dprintf1("Returning error %d.\n", err);
2047dd7cddfSDavid du Colombier else
2057dd7cddfSDavid du Colombier dprintf3("%s(%d): Returning error %d.\n",
2067dd7cddfSDavid du Colombier (const char *)file, line, err);
2077dd7cddfSDavid du Colombier }
2087dd7cddfSDavid du Colombier return err;
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier
2117dd7cddfSDavid du Colombier /* Check for interrupts before a return. */
2127dd7cddfSDavid du Colombier int
gs_return_check_interrupt(const gs_memory_t * mem,int code)213*593dc095SDavid du Colombier gs_return_check_interrupt(const gs_memory_t *mem, int code)
2147dd7cddfSDavid du Colombier {
2157dd7cddfSDavid du Colombier if (code < 0)
2167dd7cddfSDavid du Colombier return code;
2177dd7cddfSDavid du Colombier {
218*593dc095SDavid du Colombier int icode = gp_check_interrupts(mem);
2197dd7cddfSDavid du Colombier
2207dd7cddfSDavid du Colombier return (icode == 0 ? code :
2217dd7cddfSDavid du Colombier gs_note_error((icode > 0 ? gs_error_interrupt : icode)));
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier }
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier /* ------ Substitutes for missing C library functions ------ */
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier #ifdef MEMORY__NEED_MEMMOVE /* see memory_.h */
2287dd7cddfSDavid du Colombier /* Copy bytes like memcpy, guaranteed to handle overlap correctly. */
2297dd7cddfSDavid du Colombier /* ANSI C defines the returned value as being the src argument, */
2307dd7cddfSDavid du Colombier /* but with the const restriction removed! */
2317dd7cddfSDavid du Colombier void *
gs_memmove(void * dest,const void * src,size_t len)2327dd7cddfSDavid du Colombier gs_memmove(void *dest, const void *src, size_t len)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier if (!len)
2357dd7cddfSDavid du Colombier return (void *)src;
2367dd7cddfSDavid du Colombier #define bdest ((byte *)dest)
2377dd7cddfSDavid du Colombier #define bsrc ((const byte *)src)
2387dd7cddfSDavid du Colombier /* We use len-1 for comparisons because adding len */
2397dd7cddfSDavid du Colombier /* might produce an offset overflow on segmented systems. */
2407dd7cddfSDavid du Colombier if (PTR_LE(bdest, bsrc)) {
2417dd7cddfSDavid du Colombier register byte *end = bdest + (len - 1);
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier if (PTR_LE(bsrc, end)) {
2447dd7cddfSDavid du Colombier /* Source overlaps destination from above. */
2457dd7cddfSDavid du Colombier register const byte *from = bsrc;
2467dd7cddfSDavid du Colombier register byte *to = bdest;
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier for (;;) {
2497dd7cddfSDavid du Colombier *to = *from;
2507dd7cddfSDavid du Colombier if (to >= end) /* faster than = */
2517dd7cddfSDavid du Colombier return (void *)src;
2527dd7cddfSDavid du Colombier to++;
2537dd7cddfSDavid du Colombier from++;
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier }
2567dd7cddfSDavid du Colombier } else {
2577dd7cddfSDavid du Colombier register const byte *from = bsrc + (len - 1);
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier if (PTR_LE(bdest, from)) {
2607dd7cddfSDavid du Colombier /* Source overlaps destination from below. */
2617dd7cddfSDavid du Colombier register const byte *end = bsrc;
2627dd7cddfSDavid du Colombier register byte *to = bdest + (len - 1);
2637dd7cddfSDavid du Colombier
2647dd7cddfSDavid du Colombier for (;;) {
2657dd7cddfSDavid du Colombier *to = *from;
2667dd7cddfSDavid du Colombier if (from <= end) /* faster than = */
2677dd7cddfSDavid du Colombier return (void *)src;
2687dd7cddfSDavid du Colombier to--;
2697dd7cddfSDavid du Colombier from--;
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier #undef bdest
2747dd7cddfSDavid du Colombier #undef bsrc
2757dd7cddfSDavid du Colombier /* No overlap, it's safe to use memcpy. */
2767dd7cddfSDavid du Colombier memcpy(dest, src, len);
2777dd7cddfSDavid du Colombier return (void *)src;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier #endif
2807dd7cddfSDavid du Colombier
2817dd7cddfSDavid du Colombier #ifdef MEMORY__NEED_MEMCPY /* see memory_.h */
2827dd7cddfSDavid du Colombier void *
gs_memcpy(void * dest,const void * src,size_t len)2837dd7cddfSDavid du Colombier gs_memcpy(void *dest, const void *src, size_t len)
2847dd7cddfSDavid du Colombier {
2857dd7cddfSDavid du Colombier if (len > 0) {
2867dd7cddfSDavid du Colombier #define bdest ((byte *)dest)
2877dd7cddfSDavid du Colombier #define bsrc ((const byte *)src)
2887dd7cddfSDavid du Colombier /* We can optimize this much better later on. */
2897dd7cddfSDavid du Colombier register byte *end = bdest + (len - 1);
2907dd7cddfSDavid du Colombier register const byte *from = bsrc;
2917dd7cddfSDavid du Colombier register byte *to = bdest;
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier for (;;) {
2947dd7cddfSDavid du Colombier *to = *from;
2957dd7cddfSDavid du Colombier if (to >= end) /* faster than = */
2967dd7cddfSDavid du Colombier break;
2977dd7cddfSDavid du Colombier to++;
2987dd7cddfSDavid du Colombier from++;
2997dd7cddfSDavid du Colombier }
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier #undef bdest
3027dd7cddfSDavid du Colombier #undef bsrc
3037dd7cddfSDavid du Colombier return (void *)src;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier #endif
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier #ifdef MEMORY__NEED_MEMCHR /* see memory_.h */
3087dd7cddfSDavid du Colombier /* ch should obviously be char rather than int, */
3097dd7cddfSDavid du Colombier /* but the ANSI standard declaration uses int. */
3107dd7cddfSDavid du Colombier void *
gs_memchr(const void * ptr,int ch,size_t len)3117dd7cddfSDavid du Colombier gs_memchr(const void *ptr, int ch, size_t len)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier if (len > 0) {
3147dd7cddfSDavid du Colombier register const char *p = ptr;
3157dd7cddfSDavid du Colombier register uint count = len;
3167dd7cddfSDavid du Colombier
3177dd7cddfSDavid du Colombier do {
3187dd7cddfSDavid du Colombier if (*p == (char)ch)
3197dd7cddfSDavid du Colombier return (void *)p;
3207dd7cddfSDavid du Colombier p++;
3217dd7cddfSDavid du Colombier } while (--count);
3227dd7cddfSDavid du Colombier }
3237dd7cddfSDavid du Colombier return 0;
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier #endif
3267dd7cddfSDavid du Colombier
3277dd7cddfSDavid du Colombier #ifdef MEMORY__NEED_MEMSET /* see memory_.h */
3287dd7cddfSDavid du Colombier /* ch should obviously be char rather than int, */
3297dd7cddfSDavid du Colombier /* but the ANSI standard declaration uses int. */
3307dd7cddfSDavid du Colombier void *
gs_memset(void * dest,register int ch,size_t len)3317dd7cddfSDavid du Colombier gs_memset(void *dest, register int ch, size_t len)
3327dd7cddfSDavid du Colombier {
3337dd7cddfSDavid du Colombier /*
3347dd7cddfSDavid du Colombier * This procedure is used a lot to fill large regions of images,
3357dd7cddfSDavid du Colombier * so we take some trouble to optimize it.
3367dd7cddfSDavid du Colombier */
3377dd7cddfSDavid du Colombier register char *p = dest;
3387dd7cddfSDavid du Colombier register size_t count = len;
3397dd7cddfSDavid du Colombier
3407dd7cddfSDavid du Colombier ch &= 255;
3417dd7cddfSDavid du Colombier if (len >= sizeof(long) * 3) {
3427dd7cddfSDavid du Colombier long wd = (ch << 24) | (ch << 16) | (ch << 8) | ch;
3437dd7cddfSDavid du Colombier
3447dd7cddfSDavid du Colombier while (ALIGNMENT_MOD(p, sizeof(long)))
3457dd7cddfSDavid du Colombier *p++ = (char)ch, --count;
3467dd7cddfSDavid du Colombier for (; count >= sizeof(long) * 4;
3477dd7cddfSDavid du Colombier p += sizeof(long) * 4, count -= sizeof(long) * 4
3487dd7cddfSDavid du Colombier )
3497dd7cddfSDavid du Colombier ((long *)p)[3] = ((long *)p)[2] = ((long *)p)[1] =
3507dd7cddfSDavid du Colombier ((long *)p)[0] = wd;
3517dd7cddfSDavid du Colombier switch (count >> ARCH_LOG2_SIZEOF_LONG) {
3527dd7cddfSDavid du Colombier case 3:
3537dd7cddfSDavid du Colombier *((long *)p) = wd; p += sizeof(long);
3547dd7cddfSDavid du Colombier case 2:
3557dd7cddfSDavid du Colombier *((long *)p) = wd; p += sizeof(long);
3567dd7cddfSDavid du Colombier case 1:
3577dd7cddfSDavid du Colombier *((long *)p) = wd; p += sizeof(long);
3587dd7cddfSDavid du Colombier count &= sizeof(long) - 1;
3597dd7cddfSDavid du Colombier case 0:
3607dd7cddfSDavid du Colombier default: /* can't happen */
3617dd7cddfSDavid du Colombier DO_NOTHING;
3627dd7cddfSDavid du Colombier }
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier /* Do any leftover bytes. */
3657dd7cddfSDavid du Colombier for (; count > 0; --count)
3667dd7cddfSDavid du Colombier *p++ = (char)ch;
3677dd7cddfSDavid du Colombier return dest;
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier #endif
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier #ifdef malloc__need_realloc /* see malloc_.h */
3727dd7cddfSDavid du Colombier /* Some systems have non-working implementations of realloc. */
3737dd7cddfSDavid du Colombier void *
gs_realloc(void * old_ptr,size_t old_size,size_t new_size)3747dd7cddfSDavid du Colombier gs_realloc(void *old_ptr, size_t old_size, size_t new_size)
3757dd7cddfSDavid du Colombier {
3767dd7cddfSDavid du Colombier void *new_ptr;
3777dd7cddfSDavid du Colombier
3787dd7cddfSDavid du Colombier if (new_size) {
3797dd7cddfSDavid du Colombier new_ptr = malloc(new_size);
3807dd7cddfSDavid du Colombier if (new_ptr == NULL)
3817dd7cddfSDavid du Colombier return NULL;
3827dd7cddfSDavid du Colombier } else
3837dd7cddfSDavid du Colombier new_ptr = NULL;
3847dd7cddfSDavid du Colombier /* We have to pass in the old size, since we have no way to */
3857dd7cddfSDavid du Colombier /* determine it otherwise. */
3867dd7cddfSDavid du Colombier if (old_ptr != NULL) {
3877dd7cddfSDavid du Colombier if (new_ptr != NULL)
3887dd7cddfSDavid du Colombier memcpy(new_ptr, old_ptr, min(old_size, new_size));
3897dd7cddfSDavid du Colombier free(old_ptr);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier return new_ptr;
3927dd7cddfSDavid du Colombier }
3937dd7cddfSDavid du Colombier #endif
3947dd7cddfSDavid du Colombier
3957dd7cddfSDavid du Colombier /* ------ Debugging support ------ */
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier /* Dump a region of memory. */
3987dd7cddfSDavid du Colombier void
debug_dump_bytes(const byte * from,const byte * to,const char * msg)3997dd7cddfSDavid du Colombier debug_dump_bytes(const byte * from, const byte * to, const char *msg)
4007dd7cddfSDavid du Colombier {
4017dd7cddfSDavid du Colombier const byte *p = from;
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier if (from < to && msg)
4047dd7cddfSDavid du Colombier dprintf1("%s:\n", msg);
4057dd7cddfSDavid du Colombier while (p != to) {
4067dd7cddfSDavid du Colombier const byte *q = min(p + 16, to);
4077dd7cddfSDavid du Colombier
4087dd7cddfSDavid du Colombier dprintf1("0x%lx:", (ulong) p);
4097dd7cddfSDavid du Colombier while (p != q)
4107dd7cddfSDavid du Colombier dprintf1(" %02x", *p++);
4117dd7cddfSDavid du Colombier dputc('\n');
4127dd7cddfSDavid du Colombier }
4137dd7cddfSDavid du Colombier }
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier /* Dump a bitmap. */
4167dd7cddfSDavid du Colombier void
debug_dump_bitmap(const byte * bits,uint raster,uint height,const char * msg)4177dd7cddfSDavid du Colombier debug_dump_bitmap(const byte * bits, uint raster, uint height, const char *msg)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier uint y;
4207dd7cddfSDavid du Colombier const byte *data = bits;
4217dd7cddfSDavid du Colombier
4227dd7cddfSDavid du Colombier for (y = 0; y < height; ++y, data += raster)
4237dd7cddfSDavid du Colombier debug_dump_bytes(data, data + raster, (y == 0 ? msg : NULL));
4247dd7cddfSDavid du Colombier }
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier /* Print a string. */
4277dd7cddfSDavid du Colombier void
debug_print_string(const byte * chrs,uint len)4287dd7cddfSDavid du Colombier debug_print_string(const byte * chrs, uint len)
4297dd7cddfSDavid du Colombier {
4307dd7cddfSDavid du Colombier uint i;
4317dd7cddfSDavid du Colombier
4327dd7cddfSDavid du Colombier for (i = 0; i < len; i++)
4337dd7cddfSDavid du Colombier dputc(chrs[i]);
4343ff48bf5SDavid du Colombier dflush();
4353ff48bf5SDavid du Colombier }
4363ff48bf5SDavid du Colombier
4373ff48bf5SDavid du Colombier /* Print a string in hexdump format. */
4383ff48bf5SDavid du Colombier void
debug_print_string_hex(const byte * chrs,uint len)4393ff48bf5SDavid du Colombier debug_print_string_hex(const byte * chrs, uint len)
4403ff48bf5SDavid du Colombier {
4413ff48bf5SDavid du Colombier uint i;
4423ff48bf5SDavid du Colombier
4433ff48bf5SDavid du Colombier for (i = 0; i < len; i++)
4443ff48bf5SDavid du Colombier dprintf1("%02x", chrs[i]);
4453ff48bf5SDavid du Colombier dflush();
4467dd7cddfSDavid du Colombier }
4477dd7cddfSDavid du Colombier
4487dd7cddfSDavid du Colombier /*
4497dd7cddfSDavid du Colombier * The following code prints a hex stack backtrace on Linux/Intel systems.
4507dd7cddfSDavid du Colombier * It is here to be patched into places where we need to print such a trace
4517dd7cddfSDavid du Colombier * because of gdb's inability to put breakpoints in dynamically created
4527dd7cddfSDavid du Colombier * threads.
4537dd7cddfSDavid du Colombier *
4547dd7cddfSDavid du Colombier * first_arg is the first argument of the procedure into which this code
4557dd7cddfSDavid du Colombier * is patched.
4567dd7cddfSDavid du Colombier */
4577dd7cddfSDavid du Colombier #define BACKTRACE(first_arg)\
4587dd7cddfSDavid du Colombier BEGIN\
4597dd7cddfSDavid du Colombier ulong *fp_ = (ulong *)&first_arg - 2;\
4607dd7cddfSDavid du Colombier for (; fp_ && (fp_[1] & 0xff000000) == 0x08000000; fp_ = (ulong *)*fp_)\
4617dd7cddfSDavid du Colombier dprintf2(" fp=0x%lx ip=0x%lx\n", (ulong)fp_, fp_[1]);\
4627dd7cddfSDavid du Colombier END
4637dd7cddfSDavid du Colombier
4647dd7cddfSDavid du Colombier /* ------ Arithmetic ------ */
4657dd7cddfSDavid du Colombier
4667dd7cddfSDavid du Colombier /* Compute M modulo N. Requires N > 0; guarantees 0 <= imod(M,N) < N, */
4677dd7cddfSDavid du Colombier /* regardless of the whims of the % operator for negative operands. */
4687dd7cddfSDavid du Colombier int
imod(int m,int n)4697dd7cddfSDavid du Colombier imod(int m, int n)
4707dd7cddfSDavid du Colombier {
4717dd7cddfSDavid du Colombier if (n <= 0)
4727dd7cddfSDavid du Colombier return 0; /* sanity check */
4737dd7cddfSDavid du Colombier if (m >= 0)
4747dd7cddfSDavid du Colombier return m % n;
4757dd7cddfSDavid du Colombier {
4767dd7cddfSDavid du Colombier int r = -m % n;
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier return (r == 0 ? 0 : n - r);
4797dd7cddfSDavid du Colombier }
4807dd7cddfSDavid du Colombier }
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier /* Compute the GCD of two integers. */
4837dd7cddfSDavid du Colombier int
igcd(int x,int y)4847dd7cddfSDavid du Colombier igcd(int x, int y)
4857dd7cddfSDavid du Colombier {
4867dd7cddfSDavid du Colombier int c = x, d = y;
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier if (c < 0)
4897dd7cddfSDavid du Colombier c = -c;
4907dd7cddfSDavid du Colombier if (d < 0)
4917dd7cddfSDavid du Colombier d = -d;
4927dd7cddfSDavid du Colombier while (c != 0 && d != 0)
4937dd7cddfSDavid du Colombier if (c > d)
4947dd7cddfSDavid du Colombier c %= d;
4957dd7cddfSDavid du Colombier else
4967dd7cddfSDavid du Colombier d %= c;
4977dd7cddfSDavid du Colombier return d + c; /* at most one is non-zero */
4987dd7cddfSDavid du Colombier }
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier /* Compute X such that A*X = B mod M. See gxarith.h for details. */
5017dd7cddfSDavid du Colombier int
idivmod(int a,int b,int m)5027dd7cddfSDavid du Colombier idivmod(int a, int b, int m)
5037dd7cddfSDavid du Colombier {
5047dd7cddfSDavid du Colombier /*
5057dd7cddfSDavid du Colombier * Use the approach indicated in Knuth vol. 2, section 4.5.2, Algorithm
5067dd7cddfSDavid du Colombier * X (p. 302) and exercise 15 (p. 315, solution p. 523).
5077dd7cddfSDavid du Colombier */
5087dd7cddfSDavid du Colombier int u1 = 0, u3 = m;
5097dd7cddfSDavid du Colombier int v1 = 1, v3 = a;
5107dd7cddfSDavid du Colombier /*
5117dd7cddfSDavid du Colombier * The following loop will terminate with a * u1 = gcd(a, m) mod m.
5127dd7cddfSDavid du Colombier * Then x = u1 * b / gcd(a, m) mod m. Since we require that
5137dd7cddfSDavid du Colombier * gcd(a, m) | gcd(a, b), it follows that gcd(a, m) | b, so the
5147dd7cddfSDavid du Colombier * division is exact.
5157dd7cddfSDavid du Colombier */
5167dd7cddfSDavid du Colombier while (v3) {
5177dd7cddfSDavid du Colombier int q = u3 / v3, t;
5187dd7cddfSDavid du Colombier
5197dd7cddfSDavid du Colombier t = u1 - v1 * q, u1 = v1, v1 = t;
5207dd7cddfSDavid du Colombier t = u3 - v3 * q, u3 = v3, v3 = t;
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier return imod(u1 * b / igcd(a, m), m);
5237dd7cddfSDavid du Colombier }
5247dd7cddfSDavid du Colombier
5257dd7cddfSDavid du Colombier /* Compute floor(log2(N)). Requires N > 0. */
5267dd7cddfSDavid du Colombier int
ilog2(int n)5277dd7cddfSDavid du Colombier ilog2(int n)
5287dd7cddfSDavid du Colombier {
5297dd7cddfSDavid du Colombier int m = n, l = 0;
5307dd7cddfSDavid du Colombier
5317dd7cddfSDavid du Colombier while (m >= 16)
5327dd7cddfSDavid du Colombier m >>= 4, l += 4;
5337dd7cddfSDavid du Colombier return
534*593dc095SDavid du Colombier (m <= 1 ? l :
5357dd7cddfSDavid du Colombier "\000\000\001\001\002\002\002\002\003\003\003\003\003\003\003\003"[m] + l);
5367dd7cddfSDavid du Colombier }
5377dd7cddfSDavid du Colombier
5387dd7cddfSDavid du Colombier #if defined(NEED_SET_FMUL2FIXED) && !USE_ASM
5397dd7cddfSDavid du Colombier
5407dd7cddfSDavid du Colombier /*
5417dd7cddfSDavid du Colombier * Floating multiply with fixed result, for avoiding floating point in
5427dd7cddfSDavid du Colombier * common coordinate transformations. Assumes IEEE representation,
5437dd7cddfSDavid du Colombier * 16-bit short, 32-bit long. Optimized for the case where the first
5447dd7cddfSDavid du Colombier * operand has no more than 16 mantissa bits, e.g., where it is a user space
5457dd7cddfSDavid du Colombier * coordinate (which are often integers).
5467dd7cddfSDavid du Colombier *
5477dd7cddfSDavid du Colombier * The assembly language version of this code is actually faster than
5487dd7cddfSDavid du Colombier * the FPU, if the code is compiled with FPU_TYPE=0 (which requires taking
5497dd7cddfSDavid du Colombier * a trap on every FPU operation). If there is no FPU, the assembly
5507dd7cddfSDavid du Colombier * language version of this code is over 10 times as fast as the emulated FPU.
5517dd7cddfSDavid du Colombier */
5527dd7cddfSDavid du Colombier int
set_fmul2fixed_(fixed * pr,long a,long b)5537dd7cddfSDavid du Colombier set_fmul2fixed_(fixed * pr, long /*float */ a, long /*float */ b)
5547dd7cddfSDavid du Colombier {
5557dd7cddfSDavid du Colombier ulong ma = (ushort)(a >> 8) | 0x8000;
5567dd7cddfSDavid du Colombier ulong mb = (ushort)(b >> 8) | 0x8000;
5577dd7cddfSDavid du Colombier int e = 260 + _fixed_shift - ( ((byte)(a >> 23)) + ((byte)(b >> 23)) );
5587dd7cddfSDavid du Colombier ulong p1 = ma * (b & 0xff);
5597dd7cddfSDavid du Colombier ulong p = ma * mb;
5607dd7cddfSDavid du Colombier
5617dd7cddfSDavid du Colombier #define p_bits (size_of(p) * 8)
5627dd7cddfSDavid du Colombier
5637dd7cddfSDavid du Colombier if ((byte) a) { /* >16 mantissa bits */
5647dd7cddfSDavid du Colombier ulong p2 = (a & 0xff) * mb;
5657dd7cddfSDavid du Colombier
5667dd7cddfSDavid du Colombier p += ((((uint) (byte) a * (uint) (byte) b) >> 8) + p1 + p2) >> 8;
5677dd7cddfSDavid du Colombier } else
5687dd7cddfSDavid du Colombier p += p1 >> 8;
5697dd7cddfSDavid du Colombier if ((uint) e < p_bits) /* e = -1 is possible */
5707dd7cddfSDavid du Colombier p >>= e;
5717dd7cddfSDavid du Colombier else if (e >= p_bits) { /* also detects a=0 or b=0 */
5727dd7cddfSDavid du Colombier *pr = fixed_0;
5737dd7cddfSDavid du Colombier return 0;
5747dd7cddfSDavid du Colombier } else if (e >= -(p_bits - 1) || p >= 1L << (p_bits - 1 + e))
5757dd7cddfSDavid du Colombier return_error(gs_error_limitcheck);
5767dd7cddfSDavid du Colombier else
5777dd7cddfSDavid du Colombier p <<= -e;
5787dd7cddfSDavid du Colombier *pr = ((a ^ b) < 0 ? -p : p);
5797dd7cddfSDavid du Colombier return 0;
5807dd7cddfSDavid du Colombier }
5817dd7cddfSDavid du Colombier int
set_dfmul2fixed_(fixed * pr,ulong xalo,long b,long xahi)5827dd7cddfSDavid du Colombier set_dfmul2fixed_(fixed * pr, ulong /*double lo */ xalo, long /*float */ b, long /*double hi */ xahi)
5837dd7cddfSDavid du Colombier {
5847dd7cddfSDavid du Colombier return set_fmul2fixed_(pr,
5857dd7cddfSDavid du Colombier (xahi & (3L << 30)) +
5867dd7cddfSDavid du Colombier ((xahi << 3) & 0x3ffffff8) +
5877dd7cddfSDavid du Colombier (xalo >> 29),
5887dd7cddfSDavid du Colombier b);
5897dd7cddfSDavid du Colombier }
5907dd7cddfSDavid du Colombier
5917dd7cddfSDavid du Colombier #endif /* NEED_SET_FMUL2FIXED */
5927dd7cddfSDavid du Colombier
5937dd7cddfSDavid du Colombier #if USE_FPU_FIXED
5947dd7cddfSDavid du Colombier
5957dd7cddfSDavid du Colombier /*
5967dd7cddfSDavid du Colombier * Convert from floating point to fixed point with scaling.
5977dd7cddfSDavid du Colombier * These are efficient algorithms for FPU-less machines.
5987dd7cddfSDavid du Colombier */
5997dd7cddfSDavid du Colombier #define mbits_float 23
6007dd7cddfSDavid du Colombier #define mbits_double 20
6017dd7cddfSDavid du Colombier int
set_float2fixed_(fixed * pr,long vf,int frac_bits)6027dd7cddfSDavid du Colombier set_float2fixed_(fixed * pr, long /*float */ vf, int frac_bits)
6037dd7cddfSDavid du Colombier {
6047dd7cddfSDavid du Colombier fixed mantissa;
6057dd7cddfSDavid du Colombier int shift;
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier if (!(vf & 0x7f800000)) {
6087dd7cddfSDavid du Colombier *pr = fixed_0;
6097dd7cddfSDavid du Colombier return 0;
6107dd7cddfSDavid du Colombier }
6117dd7cddfSDavid du Colombier mantissa = (fixed) ((vf & 0x7fffff) | 0x800000);
6127dd7cddfSDavid du Colombier shift = ((vf >> 23) & 255) - (127 + 23) + frac_bits;
6137dd7cddfSDavid du Colombier if (shift >= 0) {
6147dd7cddfSDavid du Colombier if (shift >= sizeof(fixed) * 8 - 24)
6157dd7cddfSDavid du Colombier return_error(gs_error_limitcheck);
6167dd7cddfSDavid du Colombier if (vf < 0)
6177dd7cddfSDavid du Colombier mantissa = -mantissa;
6187dd7cddfSDavid du Colombier *pr = (fixed) (mantissa << shift);
6197dd7cddfSDavid du Colombier } else
6207dd7cddfSDavid du Colombier *pr = (shift < -24 ? fixed_0 :
6217dd7cddfSDavid du Colombier vf < 0 ? -(fixed) (mantissa >> -shift) : /* truncate */
6227dd7cddfSDavid du Colombier (fixed) (mantissa >> -shift));
6237dd7cddfSDavid du Colombier return 0;
6247dd7cddfSDavid du Colombier }
6257dd7cddfSDavid du Colombier int
set_double2fixed_(fixed * pr,ulong lo,long hi,int frac_bits)6267dd7cddfSDavid du Colombier set_double2fixed_(fixed * pr, ulong /*double lo */ lo,
6277dd7cddfSDavid du Colombier long /*double hi */ hi, int frac_bits)
6287dd7cddfSDavid du Colombier {
6297dd7cddfSDavid du Colombier fixed mantissa;
6307dd7cddfSDavid du Colombier int shift;
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier if (!(hi & 0x7ff00000)) {
6337dd7cddfSDavid du Colombier *pr = fixed_0;
6347dd7cddfSDavid du Colombier return 0;
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier /* We only use 31 bits of mantissa even if sizeof(long) > 4. */
6377dd7cddfSDavid du Colombier mantissa = (fixed) (((hi & 0xfffff) << 10) | (lo >> 22) | 0x40000000);
6387dd7cddfSDavid du Colombier shift = ((hi >> 20) & 2047) - (1023 + 30) + frac_bits;
6397dd7cddfSDavid du Colombier if (shift > 0)
6407dd7cddfSDavid du Colombier return_error(gs_error_limitcheck);
6417dd7cddfSDavid du Colombier *pr = (shift < -30 ? fixed_0 :
6427dd7cddfSDavid du Colombier hi < 0 ? -(fixed) (mantissa >> -shift) : /* truncate */
6437dd7cddfSDavid du Colombier (fixed) (mantissa >> -shift));
6447dd7cddfSDavid du Colombier return 0;
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier /*
6477dd7cddfSDavid du Colombier * Given a fixed value x with fbits bits of fraction, set v to the mantissa
6487dd7cddfSDavid du Colombier * (left-justified in 32 bits) and f to the exponent word of the
6497dd7cddfSDavid du Colombier * corresponding floating-point value with mbits bits of mantissa in the
6507dd7cddfSDavid du Colombier * first word. (The exponent part of f is biased by -1, because we add the
6517dd7cddfSDavid du Colombier * top 1-bit of the mantissa to it.)
6527dd7cddfSDavid du Colombier */
6537dd7cddfSDavid du Colombier static const byte f2f_shifts[] =
6547dd7cddfSDavid du Colombier {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
6557dd7cddfSDavid du Colombier
6567dd7cddfSDavid du Colombier #define f2f_declare(v, f)\
6577dd7cddfSDavid du Colombier ulong v;\
6587dd7cddfSDavid du Colombier long f
6597dd7cddfSDavid du Colombier #define f2f(x, v, f, mbits, fbits)\
6607dd7cddfSDavid du Colombier if ( x < 0 )\
6617dd7cddfSDavid du Colombier f = 0xc0000000 + (29 << mbits) - ((long)fbits << mbits), v = -x;\
6627dd7cddfSDavid du Colombier else\
6637dd7cddfSDavid du Colombier f = 0x40000000 + (29 << mbits) - ((long)fbits << mbits), v = x;\
6647dd7cddfSDavid du Colombier if ( v < 0x8000 )\
6657dd7cddfSDavid du Colombier v <<= 15, f -= 15 << mbits;\
6667dd7cddfSDavid du Colombier if ( v < 0x800000 )\
6677dd7cddfSDavid du Colombier v <<= 8, f -= 8 << mbits;\
6687dd7cddfSDavid du Colombier if ( v < 0x8000000 )\
6697dd7cddfSDavid du Colombier v <<= 4, f -= 4 << mbits;\
6707dd7cddfSDavid du Colombier { int shift = f2f_shifts[v >> 28];\
6717dd7cddfSDavid du Colombier v <<= shift, f -= shift << mbits;\
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier long
fixed2float_(fixed x,int frac_bits)6747dd7cddfSDavid du Colombier fixed2float_(fixed x, int frac_bits)
6757dd7cddfSDavid du Colombier {
6767dd7cddfSDavid du Colombier f2f_declare(v, f);
6777dd7cddfSDavid du Colombier
6787dd7cddfSDavid du Colombier if (x == 0)
6797dd7cddfSDavid du Colombier return 0;
6807dd7cddfSDavid du Colombier f2f(x, v, f, mbits_float, frac_bits);
6817dd7cddfSDavid du Colombier return f + (((v >> 7) + 1) >> 1);
6827dd7cddfSDavid du Colombier }
6837dd7cddfSDavid du Colombier void
set_fixed2double_(double * pd,fixed x,int frac_bits)6847dd7cddfSDavid du Colombier set_fixed2double_(double *pd, fixed x, int frac_bits)
6857dd7cddfSDavid du Colombier {
6867dd7cddfSDavid du Colombier f2f_declare(v, f);
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier if (x == 0) {
6897dd7cddfSDavid du Colombier ((long *)pd)[1 - arch_is_big_endian] = 0;
6907dd7cddfSDavid du Colombier ((ulong *) pd)[arch_is_big_endian] = 0;
6917dd7cddfSDavid du Colombier } else {
6927dd7cddfSDavid du Colombier f2f(x, v, f, mbits_double, frac_bits);
6937dd7cddfSDavid du Colombier ((long *)pd)[1 - arch_is_big_endian] = f + (v >> 11);
6947dd7cddfSDavid du Colombier ((ulong *) pd)[arch_is_big_endian] = v << 21;
6957dd7cddfSDavid du Colombier }
6967dd7cddfSDavid du Colombier }
6977dd7cddfSDavid du Colombier
6987dd7cddfSDavid du Colombier #endif /* USE_FPU_FIXED */
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier /*
7017dd7cddfSDavid du Colombier * Compute A * B / C when 0 <= B < C and A * B exceeds (or might exceed)
7027dd7cddfSDavid du Colombier * the capacity of a long.
7037dd7cddfSDavid du Colombier * Note that this procedure takes the floor, rather than truncating
7047dd7cddfSDavid du Colombier * towards zero, if A < 0. This ensures that 0 <= R < C.
7057dd7cddfSDavid du Colombier */
7067dd7cddfSDavid du Colombier
7077dd7cddfSDavid du Colombier #define num_bits (sizeof(fixed) * 8)
7087dd7cddfSDavid du Colombier #define half_bits (num_bits / 2)
7097dd7cddfSDavid du Colombier #define half_mask ((1L << half_bits) - 1)
7107dd7cddfSDavid du Colombier
7117dd7cddfSDavid du Colombier /*
7127dd7cddfSDavid du Colombier * If doubles aren't wide enough, we lose too much precision by using double
7137dd7cddfSDavid du Colombier * arithmetic: we have to use the slower, accurate fixed-point algorithm.
7143ff48bf5SDavid du Colombier * See the simpler implementation below for more information.
7157dd7cddfSDavid du Colombier */
7163ff48bf5SDavid du Colombier #define MAX_OTHER_FACTOR_BITS\
7173ff48bf5SDavid du Colombier (ARCH_DOUBLE_MANTISSA_BITS - ARCH_SIZEOF_FIXED * 8)
7183ff48bf5SDavid du Colombier #define ROUND_BITS\
7193ff48bf5SDavid du Colombier (ARCH_SIZEOF_FIXED * 8 * 2 - ARCH_DOUBLE_MANTISSA_BITS)
7203ff48bf5SDavid du Colombier
7213ff48bf5SDavid du Colombier #if USE_FPU_FIXED || ROUND_BITS >= MAX_OTHER_FACTOR_BITS - 1
7227dd7cddfSDavid du Colombier
7237dd7cddfSDavid du Colombier #ifdef DEBUG
7247dd7cddfSDavid du Colombier struct {
7257dd7cddfSDavid du Colombier long mnanb, mnab, manb, mab, mnc, mdq, mde, mds, mqh, mql;
7267dd7cddfSDavid du Colombier } fmq_stat;
7277dd7cddfSDavid du Colombier # define mincr(x) ++fmq_stat.x
7287dd7cddfSDavid du Colombier #else
7297dd7cddfSDavid du Colombier # define mincr(x) DO_NOTHING
7307dd7cddfSDavid du Colombier #endif
7317dd7cddfSDavid du Colombier fixed
fixed_mult_quo(fixed signed_A,fixed B,fixed C)7327dd7cddfSDavid du Colombier fixed_mult_quo(fixed signed_A, fixed B, fixed C)
7337dd7cddfSDavid du Colombier {
7347dd7cddfSDavid du Colombier /* First compute A * B in double-fixed precision. */
7357dd7cddfSDavid du Colombier ulong A = (signed_A < 0 ? -signed_A : signed_A);
7367dd7cddfSDavid du Colombier long msw;
7377dd7cddfSDavid du Colombier ulong lsw;
7387dd7cddfSDavid du Colombier ulong p1;
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier if (B <= half_mask) {
7417dd7cddfSDavid du Colombier if (A <= half_mask) {
7427dd7cddfSDavid du Colombier ulong P = A * B;
7437dd7cddfSDavid du Colombier fixed Q = P / (ulong)C;
7447dd7cddfSDavid du Colombier
7457dd7cddfSDavid du Colombier mincr(mnanb);
7467dd7cddfSDavid du Colombier /* If A < 0 and the division isn't exact, take the floor. */
7477dd7cddfSDavid du Colombier return (signed_A >= 0 ? Q : Q * C == P ? -Q : ~Q /* -Q - 1 */);
7487dd7cddfSDavid du Colombier }
7497dd7cddfSDavid du Colombier /*
7507dd7cddfSDavid du Colombier * We might still have C <= half_mask, which we can
7517dd7cddfSDavid du Colombier * handle with a simpler algorithm.
7527dd7cddfSDavid du Colombier */
7537dd7cddfSDavid du Colombier lsw = (A & half_mask) * B;
7547dd7cddfSDavid du Colombier p1 = (A >> half_bits) * B;
7557dd7cddfSDavid du Colombier if (C <= half_mask) {
7567dd7cddfSDavid du Colombier fixed q0 = (p1 += lsw >> half_bits) / C;
7577dd7cddfSDavid du Colombier ulong rem = ((p1 - C * q0) << half_bits) + (lsw & half_mask);
7587dd7cddfSDavid du Colombier ulong q1 = rem / (ulong)C;
7597dd7cddfSDavid du Colombier fixed Q = (q0 << half_bits) + q1;
7607dd7cddfSDavid du Colombier
7617dd7cddfSDavid du Colombier mincr(mnc);
7627dd7cddfSDavid du Colombier /* If A < 0 and the division isn't exact, take the floor. */
7637dd7cddfSDavid du Colombier return (signed_A >= 0 ? Q : q1 * C == rem ? -Q : ~Q);
7647dd7cddfSDavid du Colombier }
7657dd7cddfSDavid du Colombier msw = p1 >> half_bits;
7667dd7cddfSDavid du Colombier mincr(manb);
7677dd7cddfSDavid du Colombier } else if (A <= half_mask) {
7687dd7cddfSDavid du Colombier p1 = A * (B >> half_bits);
7697dd7cddfSDavid du Colombier msw = p1 >> half_bits;
7707dd7cddfSDavid du Colombier lsw = A * (B & half_mask);
7717dd7cddfSDavid du Colombier mincr(mnab);
7727dd7cddfSDavid du Colombier } else { /* We have to compute all 4 products. :-( */
7737dd7cddfSDavid du Colombier ulong lo_A = A & half_mask;
7747dd7cddfSDavid du Colombier ulong hi_A = A >> half_bits;
7757dd7cddfSDavid du Colombier ulong lo_B = B & half_mask;
7767dd7cddfSDavid du Colombier ulong hi_B = B >> half_bits;
7777dd7cddfSDavid du Colombier ulong p1x = hi_A * lo_B;
7787dd7cddfSDavid du Colombier
7797dd7cddfSDavid du Colombier msw = hi_A * hi_B;
7807dd7cddfSDavid du Colombier lsw = lo_A * lo_B;
7817dd7cddfSDavid du Colombier p1 = lo_A * hi_B;
7827dd7cddfSDavid du Colombier if (p1 > max_ulong - p1x)
7837dd7cddfSDavid du Colombier msw += 1L << half_bits;
7847dd7cddfSDavid du Colombier p1 += p1x;
7857dd7cddfSDavid du Colombier msw += p1 >> half_bits;
7867dd7cddfSDavid du Colombier mincr(mab);
7877dd7cddfSDavid du Colombier }
7887dd7cddfSDavid du Colombier /* Finish up by adding the low half of p1 to the high half of lsw. */
7897dd7cddfSDavid du Colombier #if max_fixed < max_long
7907dd7cddfSDavid du Colombier p1 &= half_mask;
7917dd7cddfSDavid du Colombier #endif
7927dd7cddfSDavid du Colombier p1 <<= half_bits;
7937dd7cddfSDavid du Colombier if (p1 > max_ulong - lsw)
7947dd7cddfSDavid du Colombier msw++;
7957dd7cddfSDavid du Colombier lsw += p1;
7967dd7cddfSDavid du Colombier /*
7977dd7cddfSDavid du Colombier * Now divide the double-length product by C. Note that we know msw
7987dd7cddfSDavid du Colombier * < C (otherwise the quotient would overflow). Start by shifting
7997dd7cddfSDavid du Colombier * (msw,lsw) and C left until C >= 1 << (num_bits - 1).
8007dd7cddfSDavid du Colombier */
8017dd7cddfSDavid du Colombier {
8027dd7cddfSDavid du Colombier ulong denom = C;
8037dd7cddfSDavid du Colombier int shift = 0;
8047dd7cddfSDavid du Colombier
8057dd7cddfSDavid du Colombier #define bits_4th (num_bits / 4)
8067dd7cddfSDavid du Colombier if (denom < 1L << (num_bits - bits_4th)) {
8077dd7cddfSDavid du Colombier mincr(mdq);
8087dd7cddfSDavid du Colombier denom <<= bits_4th, shift += bits_4th;
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier #undef bits_4th
8117dd7cddfSDavid du Colombier #define bits_8th (num_bits / 8)
8127dd7cddfSDavid du Colombier if (denom < 1L << (num_bits - bits_8th)) {
8137dd7cddfSDavid du Colombier mincr(mde);
8147dd7cddfSDavid du Colombier denom <<= bits_8th, shift += bits_8th;
8157dd7cddfSDavid du Colombier }
8167dd7cddfSDavid du Colombier #undef bits_8th
8173ff48bf5SDavid du Colombier while (!(denom & (-1L << (num_bits - 1)))) {
8187dd7cddfSDavid du Colombier mincr(mds);
8197dd7cddfSDavid du Colombier denom <<= 1, ++shift;
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier msw = (msw << shift) + (lsw >> (num_bits - shift));
8227dd7cddfSDavid du Colombier lsw <<= shift;
8237dd7cddfSDavid du Colombier #if max_fixed < max_long
8247dd7cddfSDavid du Colombier lsw &= (1L << (sizeof(fixed) * 8)) - 1;
8257dd7cddfSDavid du Colombier #endif
8267dd7cddfSDavid du Colombier /* Compute a trial upper-half quotient. */
8277dd7cddfSDavid du Colombier {
8287dd7cddfSDavid du Colombier ulong hi_D = denom >> half_bits;
8297dd7cddfSDavid du Colombier ulong lo_D = denom & half_mask;
8307dd7cddfSDavid du Colombier ulong hi_Q = (ulong) msw / hi_D;
8317dd7cddfSDavid du Colombier
8327dd7cddfSDavid du Colombier /* hi_Q might be too high by 1 or 2, but it isn't too low. */
8337dd7cddfSDavid du Colombier ulong p0 = hi_Q * hi_D;
8347dd7cddfSDavid du Colombier ulong p1 = hi_Q * lo_D;
8357dd7cddfSDavid du Colombier ulong hi_P;
8367dd7cddfSDavid du Colombier
8377dd7cddfSDavid du Colombier while ((hi_P = p0 + (p1 >> half_bits)) > msw ||
8387dd7cddfSDavid du Colombier (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
8397dd7cddfSDavid du Colombier ) { /* hi_Q was too high by 1. */
8407dd7cddfSDavid du Colombier --hi_Q;
8417dd7cddfSDavid du Colombier p0 -= hi_D;
8427dd7cddfSDavid du Colombier p1 -= lo_D;
8437dd7cddfSDavid du Colombier mincr(mqh);
8447dd7cddfSDavid du Colombier }
8457dd7cddfSDavid du Colombier p1 = (p1 & half_mask) << half_bits;
8467dd7cddfSDavid du Colombier if (p1 > lsw)
8477dd7cddfSDavid du Colombier msw--;
8487dd7cddfSDavid du Colombier lsw -= p1;
8497dd7cddfSDavid du Colombier msw -= hi_P;
8507dd7cddfSDavid du Colombier /* Now repeat to get the lower-half quotient. */
8517dd7cddfSDavid du Colombier msw = (msw << half_bits) + (lsw >> half_bits);
8527dd7cddfSDavid du Colombier #if max_fixed < max_long
8537dd7cddfSDavid du Colombier lsw &= half_mask;
8547dd7cddfSDavid du Colombier #endif
8557dd7cddfSDavid du Colombier lsw <<= half_bits;
8567dd7cddfSDavid du Colombier {
8577dd7cddfSDavid du Colombier ulong lo_Q = (ulong) msw / hi_D;
8587dd7cddfSDavid du Colombier long Q;
8597dd7cddfSDavid du Colombier
8607dd7cddfSDavid du Colombier p1 = lo_Q * lo_D;
8617dd7cddfSDavid du Colombier p0 = lo_Q * hi_D;
8627dd7cddfSDavid du Colombier while ((hi_P = p0 + (p1 >> half_bits)) > msw ||
8637dd7cddfSDavid du Colombier (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
8647dd7cddfSDavid du Colombier ) { /* lo_Q was too high by 1. */
8657dd7cddfSDavid du Colombier --lo_Q;
8667dd7cddfSDavid du Colombier p0 -= hi_D;
8677dd7cddfSDavid du Colombier p1 -= lo_D;
8687dd7cddfSDavid du Colombier mincr(mql);
8697dd7cddfSDavid du Colombier }
8707dd7cddfSDavid du Colombier Q = (hi_Q << half_bits) + lo_Q;
8717dd7cddfSDavid du Colombier return (signed_A >= 0 ? Q : p0 | p1 ? ~Q /* -Q - 1 */ : -Q);
8727dd7cddfSDavid du Colombier }
8737dd7cddfSDavid du Colombier }
8747dd7cddfSDavid du Colombier }
8757dd7cddfSDavid du Colombier }
8767dd7cddfSDavid du Colombier
8773ff48bf5SDavid du Colombier #else /* use doubles */
8787dd7cddfSDavid du Colombier
8797dd7cddfSDavid du Colombier /*
8803ff48bf5SDavid du Colombier * Compute A * B / C as above using doubles. If floating point is
8813ff48bf5SDavid du Colombier * reasonably fast, this is much faster than the fixed-point algorithm.
8827dd7cddfSDavid du Colombier */
8837dd7cddfSDavid du Colombier fixed
fixed_mult_quo(fixed signed_A,fixed B,fixed C)8847dd7cddfSDavid du Colombier fixed_mult_quo(fixed signed_A, fixed B, fixed C)
8857dd7cddfSDavid du Colombier {
8863ff48bf5SDavid du Colombier /*
8873ff48bf5SDavid du Colombier * Check whether A * B will fit in the mantissa of a double.
8883ff48bf5SDavid du Colombier */
8893ff48bf5SDavid du Colombier #define MAX_OTHER_FACTOR (1L << MAX_OTHER_FACTOR_BITS)
8907dd7cddfSDavid du Colombier if (B < MAX_OTHER_FACTOR || any_abs(signed_A) < MAX_OTHER_FACTOR) {
8917dd7cddfSDavid du Colombier #undef MAX_OTHER_FACTOR
8923ff48bf5SDavid du Colombier /*
8933ff48bf5SDavid du Colombier * The product fits, so a straightforward double computation
8943ff48bf5SDavid du Colombier * will be exact.
8953ff48bf5SDavid du Colombier */
8963ff48bf5SDavid du Colombier return (fixed)floor((double)signed_A * B / C);
8973ff48bf5SDavid du Colombier } else {
8983ff48bf5SDavid du Colombier /*
8993ff48bf5SDavid du Colombier * The product won't fit. However, the approximate product will
9003ff48bf5SDavid du Colombier * only be off by at most +/- 1/2 * (1 << ROUND_BITS) because of
9013ff48bf5SDavid du Colombier * rounding. If we add 1 << ROUND_BITS to the value of the product
9023ff48bf5SDavid du Colombier * (i.e., 1 in the least significant bit of the mantissa), the
9033ff48bf5SDavid du Colombier * result is always greater than the correct product by between 1/2
9043ff48bf5SDavid du Colombier * and 3/2 * (1 << ROUND_BITS). We know this is less than C:
9053ff48bf5SDavid du Colombier * because of the 'if' just above, we know that B >=
9063ff48bf5SDavid du Colombier * MAX_OTHER_FACTOR; since B <= C, we know C >= MAX_OTHER_FACTOR;
9073ff48bf5SDavid du Colombier * and because of the #if that chose between the two
9083ff48bf5SDavid du Colombier * implementations, we know that C >= 2 * (1 << ROUND_BITS). Hence,
9093ff48bf5SDavid du Colombier * the quotient after dividing by C will be at most 1 too large.
9103ff48bf5SDavid du Colombier */
9113ff48bf5SDavid du Colombier fixed q =
9123ff48bf5SDavid du Colombier (fixed)floor(((double)signed_A * B + (1L << ROUND_BITS)) / C);
9137dd7cddfSDavid du Colombier
9143ff48bf5SDavid du Colombier /*
9153ff48bf5SDavid du Colombier * Compute the remainder R. If the quotient was correct,
9163ff48bf5SDavid du Colombier * 0 <= R < C. If the quotient was too high, -C <= R < 0.
9173ff48bf5SDavid du Colombier */
9183ff48bf5SDavid du Colombier if (signed_A * B - q * C < 0)
9193ff48bf5SDavid du Colombier --q;
9203ff48bf5SDavid du Colombier return q;
9217dd7cddfSDavid du Colombier }
9227dd7cddfSDavid du Colombier }
9237dd7cddfSDavid du Colombier
9247dd7cddfSDavid du Colombier #endif
9257dd7cddfSDavid du Colombier
9263ff48bf5SDavid du Colombier #undef MAX_OTHER_FACTOR_BITS
9273ff48bf5SDavid du Colombier #undef ROUND_BITS
9283ff48bf5SDavid du Colombier
9297dd7cddfSDavid du Colombier #undef num_bits
9307dd7cddfSDavid du Colombier #undef half_bits
9317dd7cddfSDavid du Colombier #undef half_mask
9327dd7cddfSDavid du Colombier
9337dd7cddfSDavid du Colombier /* Trace calls on sqrt when debugging. */
9347dd7cddfSDavid du Colombier double
gs_sqrt(double x,const char * file,int line)9357dd7cddfSDavid du Colombier gs_sqrt(double x, const char *file, int line)
9367dd7cddfSDavid du Colombier {
9377dd7cddfSDavid du Colombier if (gs_debug_c('~')) {
9383ff48bf5SDavid du Colombier dprintf3("[~]sqrt(%g) at %s:%d\n", x, (const char *)file, line);
9393ff48bf5SDavid du Colombier dflush();
9407dd7cddfSDavid du Colombier }
9413ff48bf5SDavid du Colombier return orig_sqrt(x);
9427dd7cddfSDavid du Colombier }
9437dd7cddfSDavid du Colombier
9447dd7cddfSDavid du Colombier /*
9457dd7cddfSDavid du Colombier * Define sine and cosine functions that take angles in degrees rather than
9467dd7cddfSDavid du Colombier * radians, and that are implemented efficiently on machines with slow
9477dd7cddfSDavid du Colombier * (or no) floating point.
9487dd7cddfSDavid du Colombier */
9497dd7cddfSDavid du Colombier #if USE_FPU < 0 /****** maybe should be <= 0 ? ***** */
9507dd7cddfSDavid du Colombier
9517dd7cddfSDavid du Colombier #define sin0 0.00000000000000000
9527dd7cddfSDavid du Colombier #define sin1 0.01745240643728351
9537dd7cddfSDavid du Colombier #define sin2 0.03489949670250097
9547dd7cddfSDavid du Colombier #define sin3 0.05233595624294383
9557dd7cddfSDavid du Colombier #define sin4 0.06975647374412530
9567dd7cddfSDavid du Colombier #define sin5 0.08715574274765817
9577dd7cddfSDavid du Colombier #define sin6 0.10452846326765346
9587dd7cddfSDavid du Colombier #define sin7 0.12186934340514748
9597dd7cddfSDavid du Colombier #define sin8 0.13917310096006544
9607dd7cddfSDavid du Colombier #define sin9 0.15643446504023087
9617dd7cddfSDavid du Colombier #define sin10 0.17364817766693033
9627dd7cddfSDavid du Colombier #define sin11 0.19080899537654480
9637dd7cddfSDavid du Colombier #define sin12 0.20791169081775931
9647dd7cddfSDavid du Colombier #define sin13 0.22495105434386498
9657dd7cddfSDavid du Colombier #define sin14 0.24192189559966773
9667dd7cddfSDavid du Colombier #define sin15 0.25881904510252074
9677dd7cddfSDavid du Colombier #define sin16 0.27563735581699916
9687dd7cddfSDavid du Colombier #define sin17 0.29237170472273671
9697dd7cddfSDavid du Colombier #define sin18 0.30901699437494740
9707dd7cddfSDavid du Colombier #define sin19 0.32556815445715670
9717dd7cddfSDavid du Colombier #define sin20 0.34202014332566871
9727dd7cddfSDavid du Colombier #define sin21 0.35836794954530027
9737dd7cddfSDavid du Colombier #define sin22 0.37460659341591201
9747dd7cddfSDavid du Colombier #define sin23 0.39073112848927377
9757dd7cddfSDavid du Colombier #define sin24 0.40673664307580015
9767dd7cddfSDavid du Colombier #define sin25 0.42261826174069944
9777dd7cddfSDavid du Colombier #define sin26 0.43837114678907740
9787dd7cddfSDavid du Colombier #define sin27 0.45399049973954675
9797dd7cddfSDavid du Colombier #define sin28 0.46947156278589081
9807dd7cddfSDavid du Colombier #define sin29 0.48480962024633706
9817dd7cddfSDavid du Colombier #define sin30 0.50000000000000000
9827dd7cddfSDavid du Colombier #define sin31 0.51503807491005416
9837dd7cddfSDavid du Colombier #define sin32 0.52991926423320490
9847dd7cddfSDavid du Colombier #define sin33 0.54463903501502708
9857dd7cddfSDavid du Colombier #define sin34 0.55919290347074679
9867dd7cddfSDavid du Colombier #define sin35 0.57357643635104605
9877dd7cddfSDavid du Colombier #define sin36 0.58778525229247314
9887dd7cddfSDavid du Colombier #define sin37 0.60181502315204827
9897dd7cddfSDavid du Colombier #define sin38 0.61566147532565829
9907dd7cddfSDavid du Colombier #define sin39 0.62932039104983739
9917dd7cddfSDavid du Colombier #define sin40 0.64278760968653925
9927dd7cddfSDavid du Colombier #define sin41 0.65605902899050728
9937dd7cddfSDavid du Colombier #define sin42 0.66913060635885824
9947dd7cddfSDavid du Colombier #define sin43 0.68199836006249848
9957dd7cddfSDavid du Colombier #define sin44 0.69465837045899725
9967dd7cddfSDavid du Colombier #define sin45 0.70710678118654746
9977dd7cddfSDavid du Colombier #define sin46 0.71933980033865108
9987dd7cddfSDavid du Colombier #define sin47 0.73135370161917046
9997dd7cddfSDavid du Colombier #define sin48 0.74314482547739413
10007dd7cddfSDavid du Colombier #define sin49 0.75470958022277201
10017dd7cddfSDavid du Colombier #define sin50 0.76604444311897801
10027dd7cddfSDavid du Colombier #define sin51 0.77714596145697090
10037dd7cddfSDavid du Colombier #define sin52 0.78801075360672190
10047dd7cddfSDavid du Colombier #define sin53 0.79863551004729283
10057dd7cddfSDavid du Colombier #define sin54 0.80901699437494745
10067dd7cddfSDavid du Colombier #define sin55 0.81915204428899180
10077dd7cddfSDavid du Colombier #define sin56 0.82903757255504174
10087dd7cddfSDavid du Colombier #define sin57 0.83867056794542394
10097dd7cddfSDavid du Colombier #define sin58 0.84804809615642596
10107dd7cddfSDavid du Colombier #define sin59 0.85716730070211222
10117dd7cddfSDavid du Colombier #define sin60 0.86602540378443860
10127dd7cddfSDavid du Colombier #define sin61 0.87461970713939574
10137dd7cddfSDavid du Colombier #define sin62 0.88294759285892688
10147dd7cddfSDavid du Colombier #define sin63 0.89100652418836779
10157dd7cddfSDavid du Colombier #define sin64 0.89879404629916704
10167dd7cddfSDavid du Colombier #define sin65 0.90630778703664994
10177dd7cddfSDavid du Colombier #define sin66 0.91354545764260087
10187dd7cddfSDavid du Colombier #define sin67 0.92050485345244037
10197dd7cddfSDavid du Colombier #define sin68 0.92718385456678731
10207dd7cddfSDavid du Colombier #define sin69 0.93358042649720174
10217dd7cddfSDavid du Colombier #define sin70 0.93969262078590832
10227dd7cddfSDavid du Colombier #define sin71 0.94551857559931674
10237dd7cddfSDavid du Colombier #define sin72 0.95105651629515353
10247dd7cddfSDavid du Colombier #define sin73 0.95630475596303544
10257dd7cddfSDavid du Colombier #define sin74 0.96126169593831889
10267dd7cddfSDavid du Colombier #define sin75 0.96592582628906831
10277dd7cddfSDavid du Colombier #define sin76 0.97029572627599647
10287dd7cddfSDavid du Colombier #define sin77 0.97437006478523525
10297dd7cddfSDavid du Colombier #define sin78 0.97814760073380558
10307dd7cddfSDavid du Colombier #define sin79 0.98162718344766398
10317dd7cddfSDavid du Colombier #define sin80 0.98480775301220802
10327dd7cddfSDavid du Colombier #define sin81 0.98768834059513777
10337dd7cddfSDavid du Colombier #define sin82 0.99026806874157036
10347dd7cddfSDavid du Colombier #define sin83 0.99254615164132198
10357dd7cddfSDavid du Colombier #define sin84 0.99452189536827329
10367dd7cddfSDavid du Colombier #define sin85 0.99619469809174555
10377dd7cddfSDavid du Colombier #define sin86 0.99756405025982420
10387dd7cddfSDavid du Colombier #define sin87 0.99862953475457383
10397dd7cddfSDavid du Colombier #define sin88 0.99939082701909576
10407dd7cddfSDavid du Colombier #define sin89 0.99984769515639127
10417dd7cddfSDavid du Colombier #define sin90 1.00000000000000000
10427dd7cddfSDavid du Colombier
10437dd7cddfSDavid du Colombier private const double sin_table[361] =
10447dd7cddfSDavid du Colombier {
10457dd7cddfSDavid du Colombier sin0,
10467dd7cddfSDavid du Colombier sin1, sin2, sin3, sin4, sin5, sin6, sin7, sin8, sin9, sin10,
10477dd7cddfSDavid du Colombier sin11, sin12, sin13, sin14, sin15, sin16, sin17, sin18, sin19, sin20,
10487dd7cddfSDavid du Colombier sin21, sin22, sin23, sin24, sin25, sin26, sin27, sin28, sin29, sin30,
10497dd7cddfSDavid du Colombier sin31, sin32, sin33, sin34, sin35, sin36, sin37, sin38, sin39, sin40,
10507dd7cddfSDavid du Colombier sin41, sin42, sin43, sin44, sin45, sin46, sin47, sin48, sin49, sin50,
10517dd7cddfSDavid du Colombier sin51, sin52, sin53, sin54, sin55, sin56, sin57, sin58, sin59, sin60,
10527dd7cddfSDavid du Colombier sin61, sin62, sin63, sin64, sin65, sin66, sin67, sin68, sin69, sin70,
10537dd7cddfSDavid du Colombier sin71, sin72, sin73, sin74, sin75, sin76, sin77, sin78, sin79, sin80,
10547dd7cddfSDavid du Colombier sin81, sin82, sin83, sin84, sin85, sin86, sin87, sin88, sin89, sin90,
10557dd7cddfSDavid du Colombier sin89, sin88, sin87, sin86, sin85, sin84, sin83, sin82, sin81, sin80,
10567dd7cddfSDavid du Colombier sin79, sin78, sin77, sin76, sin75, sin74, sin73, sin72, sin71, sin70,
10577dd7cddfSDavid du Colombier sin69, sin68, sin67, sin66, sin65, sin64, sin63, sin62, sin61, sin60,
10587dd7cddfSDavid du Colombier sin59, sin58, sin57, sin56, sin55, sin54, sin53, sin52, sin51, sin50,
10597dd7cddfSDavid du Colombier sin49, sin48, sin47, sin46, sin45, sin44, sin43, sin42, sin41, sin40,
10607dd7cddfSDavid du Colombier sin39, sin38, sin37, sin36, sin35, sin34, sin33, sin32, sin31, sin30,
10617dd7cddfSDavid du Colombier sin29, sin28, sin27, sin26, sin25, sin24, sin23, sin22, sin21, sin20,
10627dd7cddfSDavid du Colombier sin19, sin18, sin17, sin16, sin15, sin14, sin13, sin12, sin11, sin10,
10637dd7cddfSDavid du Colombier sin9, sin8, sin7, sin6, sin5, sin4, sin3, sin2, sin1, sin0,
10647dd7cddfSDavid du Colombier -sin1, -sin2, -sin3, -sin4, -sin5, -sin6, -sin7, -sin8, -sin9, -sin10,
10657dd7cddfSDavid du Colombier -sin11, -sin12, -sin13, -sin14, -sin15, -sin16, -sin17, -sin18, -sin19, -sin20,
10667dd7cddfSDavid du Colombier -sin21, -sin22, -sin23, -sin24, -sin25, -sin26, -sin27, -sin28, -sin29, -sin30,
10677dd7cddfSDavid du Colombier -sin31, -sin32, -sin33, -sin34, -sin35, -sin36, -sin37, -sin38, -sin39, -sin40,
10687dd7cddfSDavid du Colombier -sin41, -sin42, -sin43, -sin44, -sin45, -sin46, -sin47, -sin48, -sin49, -sin50,
10697dd7cddfSDavid du Colombier -sin51, -sin52, -sin53, -sin54, -sin55, -sin56, -sin57, -sin58, -sin59, -sin60,
10707dd7cddfSDavid du Colombier -sin61, -sin62, -sin63, -sin64, -sin65, -sin66, -sin67, -sin68, -sin69, -sin70,
10717dd7cddfSDavid du Colombier -sin71, -sin72, -sin73, -sin74, -sin75, -sin76, -sin77, -sin78, -sin79, -sin80,
10727dd7cddfSDavid du Colombier -sin81, -sin82, -sin83, -sin84, -sin85, -sin86, -sin87, -sin88, -sin89, -sin90,
10737dd7cddfSDavid du Colombier -sin89, -sin88, -sin87, -sin86, -sin85, -sin84, -sin83, -sin82, -sin81, -sin80,
10747dd7cddfSDavid du Colombier -sin79, -sin78, -sin77, -sin76, -sin75, -sin74, -sin73, -sin72, -sin71, -sin70,
10757dd7cddfSDavid du Colombier -sin69, -sin68, -sin67, -sin66, -sin65, -sin64, -sin63, -sin62, -sin61, -sin60,
10767dd7cddfSDavid du Colombier -sin59, -sin58, -sin57, -sin56, -sin55, -sin54, -sin53, -sin52, -sin51, -sin50,
10777dd7cddfSDavid du Colombier -sin49, -sin48, -sin47, -sin46, -sin45, -sin44, -sin43, -sin42, -sin41, -sin40,
10787dd7cddfSDavid du Colombier -sin39, -sin38, -sin37, -sin36, -sin35, -sin34, -sin33, -sin32, -sin31, -sin30,
10797dd7cddfSDavid du Colombier -sin29, -sin28, -sin27, -sin26, -sin25, -sin24, -sin23, -sin22, -sin21, -sin20,
10807dd7cddfSDavid du Colombier -sin19, -sin18, -sin17, -sin16, -sin15, -sin14, -sin13, -sin12, -sin11, -sin10,
10817dd7cddfSDavid du Colombier -sin9, -sin8, -sin7, -sin6, -sin5, -sin4, -sin3, -sin2, -sin1, -sin0
10827dd7cddfSDavid du Colombier };
10837dd7cddfSDavid du Colombier
10847dd7cddfSDavid du Colombier double
gs_sin_degrees(double ang)10857dd7cddfSDavid du Colombier gs_sin_degrees(double ang)
10867dd7cddfSDavid du Colombier {
10877dd7cddfSDavid du Colombier int ipart;
10887dd7cddfSDavid du Colombier
10897dd7cddfSDavid du Colombier if (is_fneg(ang))
10907dd7cddfSDavid du Colombier ang = 180 - ang;
10917dd7cddfSDavid du Colombier ipart = (int)ang;
10927dd7cddfSDavid du Colombier if (ipart >= 360) {
10937dd7cddfSDavid du Colombier int arem = ipart % 360;
10947dd7cddfSDavid du Colombier
10957dd7cddfSDavid du Colombier ang -= (ipart - arem);
10967dd7cddfSDavid du Colombier ipart = arem;
10977dd7cddfSDavid du Colombier }
10987dd7cddfSDavid du Colombier return
10997dd7cddfSDavid du Colombier (ang == ipart ? sin_table[ipart] :
11007dd7cddfSDavid du Colombier sin_table[ipart] + (sin_table[ipart + 1] - sin_table[ipart]) *
11017dd7cddfSDavid du Colombier (ang - ipart));
11027dd7cddfSDavid du Colombier }
11037dd7cddfSDavid du Colombier
11047dd7cddfSDavid du Colombier double
gs_cos_degrees(double ang)11057dd7cddfSDavid du Colombier gs_cos_degrees(double ang)
11067dd7cddfSDavid du Colombier {
11077dd7cddfSDavid du Colombier int ipart;
11087dd7cddfSDavid du Colombier
11097dd7cddfSDavid du Colombier if (is_fneg(ang))
11107dd7cddfSDavid du Colombier ang = 90 - ang;
11117dd7cddfSDavid du Colombier else
11127dd7cddfSDavid du Colombier ang += 90;
11137dd7cddfSDavid du Colombier ipart = (int)ang;
11147dd7cddfSDavid du Colombier if (ipart >= 360) {
11157dd7cddfSDavid du Colombier int arem = ipart % 360;
11167dd7cddfSDavid du Colombier
11177dd7cddfSDavid du Colombier ang -= (ipart - arem);
11187dd7cddfSDavid du Colombier ipart = arem;
11197dd7cddfSDavid du Colombier }
11207dd7cddfSDavid du Colombier return
11217dd7cddfSDavid du Colombier (ang == ipart ? sin_table[ipart] :
11227dd7cddfSDavid du Colombier sin_table[ipart] + (sin_table[ipart + 1] - sin_table[ipart]) *
11237dd7cddfSDavid du Colombier (ang - ipart));
11247dd7cddfSDavid du Colombier }
11257dd7cddfSDavid du Colombier
11267dd7cddfSDavid du Colombier void
gs_sincos_degrees(double ang,gs_sincos_t * psincos)11277dd7cddfSDavid du Colombier gs_sincos_degrees(double ang, gs_sincos_t * psincos)
11287dd7cddfSDavid du Colombier {
11297dd7cddfSDavid du Colombier psincos->sin = gs_sin_degrees(ang);
11307dd7cddfSDavid du Colombier psincos->cos = gs_cos_degrees(ang);
11317dd7cddfSDavid du Colombier psincos->orthogonal =
11327dd7cddfSDavid du Colombier (is_fzero(psincos->sin) || is_fzero(psincos->cos));
11337dd7cddfSDavid du Colombier }
11347dd7cddfSDavid du Colombier
11357dd7cddfSDavid du Colombier #else /* we have floating point */
11367dd7cddfSDavid du Colombier
11377dd7cddfSDavid du Colombier static const int isincos[5] =
11387dd7cddfSDavid du Colombier {0, 1, 0, -1, 0};
11397dd7cddfSDavid du Colombier
1140*593dc095SDavid du Colombier /* GCC with -ffast-math compiles ang/90. as ang*(1/90.), losing precission.
1141*593dc095SDavid du Colombier * This doesn't happen when the numeral is replaced with a non-const variable.
1142*593dc095SDavid du Colombier * So we define the variable to work around the GCC problem.
1143*593dc095SDavid du Colombier */
1144*593dc095SDavid du Colombier static double const_90_degrees = 90.;
1145*593dc095SDavid du Colombier
11467dd7cddfSDavid du Colombier double
gs_sin_degrees(double ang)11477dd7cddfSDavid du Colombier gs_sin_degrees(double ang)
11487dd7cddfSDavid du Colombier {
1149*593dc095SDavid du Colombier double quot = ang / const_90_degrees;
11507dd7cddfSDavid du Colombier
11517dd7cddfSDavid du Colombier if (floor(quot) == quot) {
11527dd7cddfSDavid du Colombier /*
11537dd7cddfSDavid du Colombier * We need 4.0, rather than 4, here because of non-ANSI compilers.
11547dd7cddfSDavid du Colombier * The & 3 is because quot might be negative.
11557dd7cddfSDavid du Colombier */
11567dd7cddfSDavid du Colombier return isincos[(int)fmod(quot, 4.0) & 3];
11577dd7cddfSDavid du Colombier }
11587dd7cddfSDavid du Colombier return sin(ang * (M_PI / 180));
11597dd7cddfSDavid du Colombier }
11607dd7cddfSDavid du Colombier
11617dd7cddfSDavid du Colombier double
gs_cos_degrees(double ang)11627dd7cddfSDavid du Colombier gs_cos_degrees(double ang)
11637dd7cddfSDavid du Colombier {
1164*593dc095SDavid du Colombier double quot = ang / const_90_degrees;
11657dd7cddfSDavid du Colombier
11667dd7cddfSDavid du Colombier if (floor(quot) == quot) {
11677dd7cddfSDavid du Colombier /* See above re the following line. */
11687dd7cddfSDavid du Colombier return isincos[((int)fmod(quot, 4.0) & 3) + 1];
11697dd7cddfSDavid du Colombier }
11707dd7cddfSDavid du Colombier return cos(ang * (M_PI / 180));
11717dd7cddfSDavid du Colombier }
11727dd7cddfSDavid du Colombier
11737dd7cddfSDavid du Colombier void
gs_sincos_degrees(double ang,gs_sincos_t * psincos)11747dd7cddfSDavid du Colombier gs_sincos_degrees(double ang, gs_sincos_t * psincos)
11757dd7cddfSDavid du Colombier {
1176*593dc095SDavid du Colombier double quot = ang / const_90_degrees;
11777dd7cddfSDavid du Colombier
11787dd7cddfSDavid du Colombier if (floor(quot) == quot) {
11797dd7cddfSDavid du Colombier /* See above re the following line. */
11807dd7cddfSDavid du Colombier int quads = (int)fmod(quot, 4.0) & 3;
11817dd7cddfSDavid du Colombier
11827dd7cddfSDavid du Colombier psincos->sin = isincos[quads];
11837dd7cddfSDavid du Colombier psincos->cos = isincos[quads + 1];
11847dd7cddfSDavid du Colombier psincos->orthogonal = true;
11857dd7cddfSDavid du Colombier } else {
11867dd7cddfSDavid du Colombier double arad = ang * (M_PI / 180);
11877dd7cddfSDavid du Colombier
11887dd7cddfSDavid du Colombier psincos->sin = sin(arad);
11897dd7cddfSDavid du Colombier psincos->cos = cos(arad);
11907dd7cddfSDavid du Colombier psincos->orthogonal = false;
11917dd7cddfSDavid du Colombier }
11927dd7cddfSDavid du Colombier }
11937dd7cddfSDavid du Colombier
11947dd7cddfSDavid du Colombier #endif /* USE_FPU */
11953ff48bf5SDavid du Colombier
11963ff48bf5SDavid du Colombier /*
11973ff48bf5SDavid du Colombier * Define an atan2 function that returns an angle in degrees and uses
11983ff48bf5SDavid du Colombier * the PostScript quadrant rules. Note that it may return
11993ff48bf5SDavid du Colombier * gs_error_undefinedresult.
12003ff48bf5SDavid du Colombier */
12013ff48bf5SDavid du Colombier int
gs_atan2_degrees(double y,double x,double * pangle)12023ff48bf5SDavid du Colombier gs_atan2_degrees(double y, double x, double *pangle)
12033ff48bf5SDavid du Colombier {
12043ff48bf5SDavid du Colombier if (y == 0) { /* on X-axis, special case */
12053ff48bf5SDavid du Colombier if (x == 0)
12063ff48bf5SDavid du Colombier return_error(gs_error_undefinedresult);
12073ff48bf5SDavid du Colombier *pangle = (x < 0 ? 180 : 0);
12083ff48bf5SDavid du Colombier } else {
12093ff48bf5SDavid du Colombier double result = atan2(y, x) * radians_to_degrees;
12103ff48bf5SDavid du Colombier
12113ff48bf5SDavid du Colombier if (result < 0)
12123ff48bf5SDavid du Colombier result += 360;
12133ff48bf5SDavid du Colombier *pangle = result;
12143ff48bf5SDavid du Colombier }
12153ff48bf5SDavid du Colombier return 0;
12163ff48bf5SDavid du Colombier }
1217