Created
October 23, 2011 20:35
-
-
Save ramntry/1307862 to your computer and use it in GitHub Desktop.
IEEE 754 preparation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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