/* Last edited on 2024-11-20 07:47:13 by stolfi */ /* ---------------------------------------------------------------------- */ Float flt_interpolate_lo(Float xa, Float ya, Float xb, Float yb, Float x) { demand(xa <= xb, "{xa,xb} out of order"); demand((xa <= x) && (x <= xb), "{x} out of range"); if (x == xa) { return(ya); } else if (x == xb) { return(yb); } else { ROUND_DOWN; Float dx = - (xa - xb); /* Same as {xb - xa} rounded up. */ if (ya < yb) { Float dy = yb - ya; Float r = x - xa; return(ya + dy*(r/dx)); } else { Float dy = ya - yb; Float r = xb - x; return(yb + dy*(r/dx)); } } } Float flt_interpolate_hi(Float xa, Float ya, Float xb, Float yb, Float x) { demand(xa <= xb, "{xa,xb} out of order"); demand((xa <= x) && (x <= xb), "{x} out of range"); if (x == xa) { return(ya); } else if (x == xb) { return(yb); } else { ROUND_UP; Float dx = - (xa - xb); /* Same as {xb - xa} rounded down. */ if (ya < yb) { Float dy = yb - ya; Float r = x - xa; return(ya + dy*(r/dx)); } else { Float dy = ya - yb; Float r = xb - x; return(yb + dy*(r/dx)); } } } /* ---------------------------------------------------------------------- */ /* From flt.h: */ /* Setting the IEEE rounding mode bits on a SPARC: */ extern char *ROUND_BUFP; #define ROUND_DOWN ieee_flags("set", "direction", "negative", &ROUND_BUFP) #define ROUND_UP ieee_flags("set", "direction", "positive", &ROUND_BUFP) #define ROUND_NEAR ieee_flags("set", "direction", "nearest", &ROUND_BUFP) #define ROUND_ZERO ieee_flags("set", "direction", "tozero", &ROUND_BUFP) /* From flt.h, second version: */ #define ROUND_DOWN flt_set_rounding(fp_negative) #define ROUND_UP flt_set_rounding(fp_positive) #define ROUND_NEAR flt_set_rounding(fp_nearest) #define ROUND_ZERO flt_set_rounding(fp_tozero) void flt_set_rounding (enum fp_direction_type dir); /* Sets the IEEE FP rounding direction to $dir$. */ /* Was fltasm.s */ ! Setting the IEEE rounding mode bits on a SPARC ! See flt.h .text .align 4 .global _flt_set_rounding .proc 020 _flt_set_rounding: !#PROLOGUE# 0 save %sp,-120,%sp !#PROLOGUE# 1 and %i0,3,%o0 ! Ensure argument is in [0..3] sethi %hi(_fp_direction),%o1 ! Update fp_direction st %o0,[%o1+%lo(_fp_direction)] ! " sll %o0,30,%o0 ! Shift new rounding dir to proper place set 0xc0000000,%o1 ! Mask of rounding direction bits st %fsr,[%fp+68] ! Get FP status register ld [%fp+68],%o2 ! (must we go through memory?) andn %o2,%o1,%o2 or %o0,%o2,%o0 st %o0,[%fp+68] ! Set FP status register ld [%fp+68],%fsr ! (must we go through memory?) ret restore /* From pcode.c: */ char *pcode_get_line(FILE *f) { int mc = 10; int nc = 0; char *s = (char *) malloc(mc*sizeof(char)); int c; do { c = getc(f); if ((c == EOF) || (c == '\n')) c = '\000'; if (c == '\t') c = ' '; if ((nc > 0) || (c != ' ')) { if (nc >= mc) { mc *= 2; s = (char *) realloc ((void *) s, mc*sizeof(char)); } affirm (s != NULL, "psc_get_line: alloc failed"); s[nc] = c; nc++; } } while (c != '\000'); return (s); } /* ---------------------------------------------------------------------- */ /* From flt_random_mag */ { int32_t w = dev + dev + 1; uint32_t mask = 1; /* find smallest all-ones mask that is no less than 2*dev + 1: */ while ((mask & w) != w) mask = ((mask << 1) | 1); /* Generate random integer in range [0..2*dev]: */ /* Compute exponent "exp": */ do { exp = (rand() & mask); } while (exp >= w); /* Compute exponent: */ exp = avg + (exp - dev); } /* ---------------------------------------------------------------------- */ /* From fltasm-knueppel.a: */ .data .align 4 _flt_sr_round_near: .word 0x00000000 _flt_sr_round_zero: .word 0x40000000 _flt_sr_round_up: .word 0x80000000 _flt_sr_round_down: .word 0xC0000000 .text .align 4 .global _flt_round_up .proc 020 _flt_round_up: sethi %hi(_flt_sr_round_up),%g2 retl ld [%g2+%lo(_flt_sr_round_up)],%fsr .align 4 .global _flt_round_down .proc 020 _flt_round_down: sethi %hi(_flt_sr_round_down),%g2 retl ld [%g2+%lo(_flt_sr_round_down)],%fsr .align 4 .global _flt_round_near .proc 020 _flt_round_near: sethi %hi(_flt_sr_round_near),%g2 retl ld [%g2+%lo(_flt_sr_round_near)],%fsr