celestia/src/bigfix.cpp

188 lines
3.3 KiB
C++

// bigfix.cpp
//
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <math.h>
#include <stdio.h>
#include "bigfix.h"
/*** Constructors ***/
// Create a BigFix initialized to zero
BigFix::BigFix()
{
for (int i = 0; i < N_WORDS; i++)
n[i] = 0;
}
BigFix::BigFix(int i)
{
n[N_WORDS / 2] = (unsigned short) (i & 0xffff);
n[N_WORDS / 2 + 1] = (unsigned short) ((i >> 16) & 0xffff);
// Sign extend if negative
if (i < 0)
{
for (int j = N_WORDS / 2 + 2; j < N_WORDS; j++)
n[j] = 0xffff;
}
}
BigFix::BigFix(double d)
{
int sign = 1;
if (d < 0)
{
sign = -1;
d = -d;
}
double e = floor(d / (65536.0 * 65536.0 * 65536.0));
// Check for overflow
if (e < 32767)
{
n[7] = (unsigned short) e;
d -= n[7] * 65536 * 65536 * 65536;
n[6] = (unsigned short) (d / (65536.0 * 65536.0));
d -= n[6] * 65536 * 65536;
n[5] = (unsigned short) (d / 65536);
d -= n[5] * 65536;
n[4] = (unsigned short) d;
d -= n[4];
n[3] = (unsigned short) (d * 65536);
d -= n[3] / 65536;
n[2] = (unsigned short) (d * 65536 * 65536);
d -= n[2] / 65536;
n[1] = (unsigned short) (d * 65536 * 65536 * 65536);
d -= n[1] / 65536;
n[0] = (unsigned short) (d * 65536 * 65536 * 65536 * 65536);
}
if (sign < 0)
*this = -*this;
}
BigFix::operator double() const
{
double d = 0;
double e = 1.0 / (65536.0 * 65536.0 * 65536.0 * 65536.0);
BigFix f;
if ((n[N_WORDS - 1] & 0x8000) == 0)
f = *this;
else
f = -*this;
for (int i = 0; i < N_WORDS; i++)
{
d += e * f.n[i];
e *= 65536;
}
return ((n[N_WORDS - 1] & 0x8000) == 0) ? d : -d;
}
BigFix::operator float() const
{
return (float) (double) *this;
}
BigFix BigFix::operator-() const
{
int i;
BigFix f;
for (i = 0; i < N_WORDS; i++)
f.n[i] = ~n[i];
unsigned int carry = 1;
i = 0;
while (carry != 0 && i < N_WORDS)
{
unsigned int m = f.n[i] + carry;
f.n[i] = (unsigned short) (m & 0xffff);
carry = m >> 16;
i++;
}
return f;
}
BigFix operator+(BigFix a, BigFix b)
{
unsigned int carry = 0;
BigFix c;
for (int i = 0; i < N_WORDS; i++)
{
unsigned int m = a.n[i] + b.n[i] + carry;
c.n[i] = (unsigned short) (m & 0xffff);
carry = m >> 16;
}
return c;
}
BigFix operator-(BigFix a, BigFix b)
{
return a + -b;
}
BigFix operator*(BigFix a, BigFix b)
{
return BigFix();
}
bool operator==(BigFix a, BigFix b)
{
for (int i = 0; i < N_WORDS; i++)
if (a.n[i] != b.n[i])
return false;
return true;
}
bool operator!=(BigFix a, BigFix b)
{
return !(a == b);
}
int BigFix::sign()
{
if ((n[N_WORDS - 1] & 0x8000) != 0)
return -1;
for (int i = 0; i < N_WORDS - 1; i++)
if (n[N_WORDS] != 0)
return 1;
return 0;
}
// For debugging
void BigFix::dump()
{
for (int i = 7; i >= 0; i--)
printf("%04x ", n[i]);
printf("\n");
}