Skip to content

Instantly share code, notes, and snippets.

@ramntry
Created October 23, 2011 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ramntry/1307862 to your computer and use it in GitHub Desktop.
Save ramntry/1307862 to your computer and use it in GitHub Desktop.
IEEE 754 preparation
// author: Roman Tereshin
// email: roman.tereshin@student.spbu.ru
// hw 05, task 02
// По содержимому памяти вывести значение типа float в экспоненциальной
// форме:
// sm*q^(Sp), где s -- знак мантиссы, m -- мантисса, q -- основание системы
// счисления, S -- знак порядка, p -- порядок числа.
// [time start] 20:06 19.10.11
// [time estimate] 01:00 00
#include <stdio.h>
/// Для разрешения побитовых операций и устранения зависимости
/// от порядка байт
union doublePrep
{
double value;
unsigned long long bits;
};
/// Расчет мантиссы с использованием только целочисленной арифметики
/// и печать ее со знаком
void printMant(doublePrep n)
{
unsigned long long mask = 1;
mask <<= 63;
char sign = mask & n.bits ? '-' : '+'; // получение знака
mask >>= 12; // установка маски под первый бит мантиссы
unsigned long long toNext = 0; // & с маской toNext определяет,
toNext = ~toNext; // есть ли еще значащие биты
unsigned long long max = toNext / 10; // для защиты от переполнения
toNext >>= 12; // ... unsigned long long mant
unsigned long long mant = 0;
unsigned long long p5 = 1; // 10 / 2 = 5 (отношение систем исчисления)
int i = 0; // нужно не потярять нули в начале малого числа
while (toNext & n.bits) // пока есть значащие биты в мантиссе
{
if (mant <= max) // и нет угрозы переполнения
{
mant *= 10; // резервируем место в записи мантиссы
p5 *= 5; // и "делим" текущее значение позиции на 2
i++; // если mant еще 0, только так можно запомнить,
} // ... что после 1. в результате есть нули
else // иначе делим напрямую
p5 /= 2;
// добавляем к мантиссе дробь вида 1 / 2^i,
if (n.bits & mask) // где i - позиция бита в двоичной мантиссе,
mant += p5; // только если бит установлен
mask >>= 1;
toNext >>=1;
}
printf("\t%c1.%0*llu", sign, i, mant);
}
// расчет и печать порядка экспоненты по основанию 2
void printExp(doublePrep n)
{
n.bits <<= 1; // сброс бита знака
n.bits >>= 53; // - / - мантиссы
int exp = n.bits; // - / - ограничений на unsigned
exp -= 1023; // - / - смещения
printf("*2^(%d)\n", exp);
}
int main(void)
{
printf("Representation of a real number in standard form with the %s",
"exponent to base 2 (send EOF (ctrl + D) to exit)\n");
printf("d = ");
doublePrep n;
while(scanf("%lf", &n.value) != EOF)
{
if (!(n.bits << 1)) // не будем различать +0 и -0
{
printf("\t0\nd = ");
continue;
}
printMant(n);
printExp(n);
printf("d = ");
}
putchar('\n');
return 0;
}
// [time done] 17:19 23.10.11
// [time real] 21:14 03
#include <stdio.h>
typedef unsigned long long llong;
/// Для разрешения побитовых операций и устранения зависимости
/// от порядка байт, а также хранения промежуточных значений
struct doublePrep
{
union
{
double value;
llong bits;
};
llong mant;
int exp;
char sign;
};
/// Расчет мантиссы с использованием только целочисленной арифметики
doublePrep calcMant(doublePrep n)
{
llong mask = 1;
mask <<= 63;
n.sign = mask & n.bits ? '-' : '+'; // получение знака
mask >>= 12; // установка маски под первый бит мантиссы
llong toNext = 0; // & с маской toNext определяет,
toNext = ~toNext; // есть ли еще значащие биты
llong max = toNext / 10; // для защиты от переполнения
toNext >>= 12; // ... llong mant
n.mant = 1;
llong p5 = 1; // 10 / 2 = 5 (отношение систем исчисления)
while (toNext & n.bits) // пока есть значащие биты в мантиссе
{
if (n.mant <= max) // и нет угрозы переполнения
{
n.mant *= 10; // резервируем место в записи мантиссы
p5 *= 5; // и "делим" текущее значение позиции на 2
}
else // иначе делим напрямую
p5 /= 2;
// добавляем к мантиссе дробь вида 1 / 2^i,
if (n.bits & mask) // где i - позиция бита в двоичной мантиссе,
n.mant += p5; // только если бит установлен
mask >>= 1;
toNext >>=1;
}
return n;
}
// расчет порядка экспоненты по основанию 2
doublePrep calcExp(doublePrep n)
{
llong lbits = n.bits;
lbits <<= 1; // сброс бита знака
lbits >>= 53; // - / - мантиссы
n.exp = lbits; // - / - ограничений на unsigned
n.exp -= 1023; // - / - смещения
return n;
}
int numDigits(llong n)
{
int i = 0;
while (n)
{
n /= 10;
i++;
}
return i;
}
doublePrep exp2exp10(doublePrep n)
{
llong mask = 1;
mask <<= 63;
if (n.exp > 0)
{
int exp10 = 1 - numDigits(n.mant);
while (n.exp)
{
if (n.mant & mask)
{
n.mant /= 10;
exp10++;
}
n.mant <<= 1;
n.exp--;
}
exp10 += numDigits(n.mant) - 1;
n.exp = exp10;
}
else if (n.exp < 0)
{
int exp10 = 0;
while (n.mant * 10 / 10 == n.mant)
n.mant *= 10;
while (n.exp)
{
n.mant >>= 1;
if (n.mant * 10 / 10 == n.mant)
{
n.mant *= 10;
exp10--;
}
n.exp++;
}
n.exp = exp10;
}
return n;
}
/// округление мантиссы до 15-16 знаков - далее мусор
doublePrep round16(doublePrep n)
{
int lastNum = 0;
llong max = 1e16;
if (n.exp < 0)
max = 1e15;
while (n.mant > max)
{
lastNum = n.mant % 10;
n.mant /= 10;
}
if (lastNum > 4) // округляем по математическим правилам
n.mant++;
while (n.mant % 10 == 0)
n.mant /= 10;
return n;
}
int main(void)
{
printf("Representation of a real number in standard form with the %s",
"exponent to base 10 (send EOF (ctrl + D) to exit)\n");
printf("d = ");
doublePrep n;
while(scanf("%lf", &n.value) != EOF)
{
if (!(n.bits << 1)) // не будем различать +0 и -0
{
printf("\t0\nd = ");
continue;
}
n = calcMant(n);
n = calcExp(n);
n = exp2exp10(n);
n = round16(n);
char buf[17];
sprintf(buf, "%llu", n.mant);
printf("\t%c%c.%se%+d\nd = ",
n.sign, buf[0], buf[1] ? buf + 1 : "0", n.exp);
}
putchar('\n');
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment