Консультация № 187325
10.05.2013, 19:01
240.47 руб.
0 21 1
Здравствуйте! У меня возникли сложности с таким вопросом:

Написать программу на С для отыскания значений машинного нуля и машинного эпсилон. с комментариями. С выводом, сколько разрядов на мантиссу и экспоненту.

При этом нужно 2 разных варианта программы. В плане чтоб не было понятно что писал 1 человек или скопированы с минимальными изменениями

Обсуждение

давно
Посетитель
7438
7205
10.05.2013, 20:32
общий
10.05.2013, 20:33
Здравствуйте!
Что понимается под "для отыскания значений машинного нуля"? И как Вы предполагаете его искать?
Данный "машинный ноль", как и "сколько разрядов на мантиссу и экспоненту" полностью и однозначно зависит от формата: float, double, long double. Непонятно, что должна делать программа...
И что такое "машинный эпсилон"?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
11.05.2013, 04:55
общий
11.05.2013, 06:14
Хм, чуть попозже попробую ответить. Могу показать пример чужой программы на данную задачу, мб прояснит суть.

[code h=200]# include <conio.h>
# include <stdio.h>

int Kolvo_bit_exponenta_double=0,Kolvo_bit_mantissa_double=0,
Kolvo_bit_znaka_double=0,posl_ed_double=0;
int Kolvo_bit_exponenta_float=0,Kolvo_bit_mantissa_float=0,
Kolvo_bit_znaka_float=0,posl_ed_float=0;


void dvoichnoe_otobrazhenie_double (double vhodnoe) //Функция отображения числа типа double из ячейки памяти
{
printf("Dvoich: " );
int A[64]; //Инициализация массива
__int64 mask, *var;
var=(__int64*) (&vhodnoe); //Преобразование указателя на double в указатель на __int64
mask=1;
for (int i=0; i<64; i++)
{
if (((*var)&(mask))== mask) A=1; //Побитное сравнение с маской
else A=0 ;
mask=mask*2; //Переброс маски на следующий бит
}
for (int i=63; i>=0; i--) //Вывод на экран инвертированного массива
{
printf ("%i",A);
if (i%8==0) printf (" "); //Разделение массива на элементы по 8 знаков
} //для более наглядного представления

if (vhodnoe==1.0) //Блок, вычисляющий и выводящий на экран
{ //количество разрядов знака, мантиссы и
for (int i=0; i<64; i++) //экспоненты
{
if (A==1) //Если в функцию отправлена 1, то, после
{ //представления её в двоичном виде, считается
Kolvo_bit_exponenta_double++; //количество единичных бит. Число бит, отведенное
if (A[i+1]==0) //под хранение экспоненты будет равно
{ //количеству единичных бит + 1.
posl_ed_double++; //Число бит, отведенное под хранение знака
} //будет равно количеству нулевых бит перед
} //первым единичным битом - 1.
if (posl_ed_double==1) //Остальные биты отведены под хранение мантиссы
Kolvo_bit_znaka_double++;
}
Kolvo_bit_exponenta_double++;
Kolvo_bit_znaka_double=Kolvo_bit_znaka_double-2;
Kolvo_bit_mantissa_double=64-Kolvo_bit_znaka_double-Kolvo_bit_exponenta_double;
printf ("Kolvo_bit_znaka_double=%i\n",Kolvo_bit_znaka_double);
printf ("Kolvo_bit_exponenta_double=%i\n",Kolvo_bit_exponenta_double);
printf ("Kolvo_bit_mantissa_double=%i\n",Kolvo_bit_mantissa_double);
}
}



void dvoichnoe_otobrazhenie_float (float vhodnoe) //Функция отображения числа типа float из ячейки памяти
{
printf("Dvoich: " );
int A[32];
__int32 mask, *var;
var=(__int32*) (&vhodnoe);
mask=1;
for (int i=0; i<32; i++)
{
if (((*var)&(mask))== mask) A=1;
else A=0 ;
mask=mask*2;
}
for (int i=31; i>=0; i--)
{
printf ("%i",A);
if (i%8==0) printf (" ");
}
printf ("\n");
if (vhodnoe==1.0)
{
for (int i=0; i<32; i++)
{
if (A==1)
{
Kolvo_bit_exponenta_float++;
if (A[i+1]==0)
{
posl_ed_float++;
}
}
if (posl_ed_float==1)
Kolvo_bit_znaka_float++;
}
Kolvo_bit_exponenta_float++;
Kolvo_bit_znaka_float=Kolvo_bit_znaka_float-2;
Kolvo_bit_mantissa_float=32-Kolvo_bit_znaka_float-Kolvo_bit_exponenta_float;
printf ("Kolvo_bit_znaka_float=%i\n",Kolvo_bit_znaka_float);
printf ("Kolvo_bit_exponenta_float=%i\n",Kolvo_bit_exponenta_float);
printf ("Kolvo_bit_mantissa_float=%i\n",Kolvo_bit_mantissa_float);
}
}



int main()
{
float eps_float_vspom=1.0, eps_float=1.0, nol_float=1.0, nol_float_vspom=1.0;
double eps_double_vspom=1.0, eps_double=1.0, nol_double=1.0, nol_double_vspom=1.0;
do //Вычисление машинного эпсилона типа float
{
eps_float_vspom = eps_float_vspom/2;
eps_float=eps_float_vspom+1;
}
while (eps_float>1);
eps_float=eps_float_vspom*2;
do //Вычисление машинного эпсилона типа double
{
eps_double_vspom = eps_double_vspom/2;
eps_double=eps_double_vspom+1;
}
while (eps_double>1);
eps_double=eps_double_vspom*2;
do //Вычисление машинного нуля типа float
{
nol_float_vspom=nol_float;
nol_float = nol_float/2;
}
while (nol_float>0);
nol_float=nol_float_vspom;
do //Вычисление машинного нуля типа double
{
nol_double_vspom=nol_double;
nol_double = nol_double/2;
}
while (nol_double>0);
nol_double=nol_double_vspom;
printf("Mashinnyi epsilon FLOAT: \t%.30e\n",eps_float);
dvoichnoe_otobrazhenie_float ( eps_float);
printf("\nMashinnyi epsilon DOUBLE: \t%.30e\n",eps_double);
dvoichnoe_otobrazhenie_double ( eps_double);
printf("\nMashinnyi nol' FLOAT: \t\t%.30e\n",nol_float);
dvoichnoe_otobrazhenie_float ( nol_float);
printf("\nMashinnyi nol' DOUBLE: \t\t%.30e\n",nol_double);
dvoichnoe_otobrazhenie_double ( nol_double);
printf("\nRaschet znaka, mantissy, exponenty: \n");
dvoichnoe_otobrazhenie_float (1.0);
dvoichnoe_otobrazhenie_double (1.0);
getch();
return 0;
}[/code]
Неизвестный
11.05.2013, 15:25
общий
А обязательно только на C, или и на C++ годится?
давно
Посетитель
7438
7205
11.05.2013, 19:09
общий
Программы более чем достаточно.
Сегодня, ближе к ночи, сделаю...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
11.05.2013, 23:42
общий
12.05.2013, 00:00
сколько разрядов на мантиссу и экспоненту.
В приведенной программе количество бит считается по формату вещественной единицы. Так и надо? В общем-то формат вещественных чисел строго определен и можно сказать сколько бит в каждом поле, не считая... Судя по условию, требуется просто расписать биты полученных чисел по полям, а не считать длины полей по формату единицы... Так как надо сделать?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
12.05.2013, 21:12
общий
Сделайте "просто расписать биты полученных чисел по полям, а не считать длины полей по формату единицы"
давно
Посетитель
7438
7205
12.05.2013, 22:56
общий
это ответ
Здравствуйте, Посетитель - 397042!
Предлагаю вот такой вариант реализации:
[code h=200]#include <conio.h>
#include <stdio.h>

//подпрограмма вывода бит вещественного числа, как последовательности байт
//параметры: адрес в памяти числа и число байт
//подпрограмма универсальная: работает как с float, так и с double
//тип данных задается количеством байт: 4 - для float, 8 - для double
//корректность параметра не проверяется!
void binary_print(unsigned char *pData, int iCount)
{
int i, j, k;
char A[64]; //буфер для формирования последовательности бит 0/1 (максимально 64)
unsigned char ch; //для приема очередного байта
int iPosSign; //позиция знака в буфере
int iExpCount; //количество бит экспоненты
int iManCount; //количество бит мантиссы

printf("Binary:"); //начинаем вывод...

//сформируем строку - последовательность бит, начиная с младшего.
for(k=i=0; i<iCount; i++) //циклим по байтам, k - позиция в буфере с байтами(битами)
{
ch = pData[i]; //очередной байт числа
for(j=0; j<8; j++) //цикл по битам байта ch,
{
A[k++] = (ch & 1) + '0'; //добавляя к младшему биту '0', получим '0' или '1'
ch>>=1; //следующий бит делаем младшим
}
}

//выводим все биты, в обратном порядке, начиная со старшего
for(i=(iCount<<3)-1; i>=0; i--) //(iCount<<3) - количество бит в числе,
{ //(iCount<<3)-1 - индекс самого старшего (знакового) бита
if (7==(i&7)) //условие для вывода пробела ПЕРЕД очередной восьмеркой бит
printf(" "); //пробел для читабельности
printf("%c", A[i]); //выводим очередной бит, как символ
}

//выводим битовые поля числа
if (iCount == 4) //для типа float
{
iPosSign = 31; //индекс бита знака
iExpCount = 8; //количество бит экспоненты
iManCount = 23; //количество бит мантиссы
}
else //для типа double
{
iPosSign = 63; //индекс бита знака
iExpCount = 11; //количество бит экспоненты
iManCount = 52; //количество бит мантиссы
}
printf("\nSign (1 bit):\t\t%c", A[iPosSign]); //знак
printf("\nExponent (%d bits):\t", iExpCount); //экспонента
for(i=0; i<iExpCount; i++)
printf("%c", A[iPosSign-i-1]); //биты экспоненты
printf("\nMantissa (%d bits):\t", iManCount); //мантисса
for(i=0; i<iManCount; i++)
printf("%c", A[iManCount-i-1]); //биты мантиссы
printf("\n\n"); //переход на новую строку и вывод еще одной пустой строки
}

int main()
{
float eps_float_vspom = 1.0,
eps_float = 1.0,
nol_float = 1.0,
nol_float_vspom = 1.0;
double eps_double_vspom = 1.0,
eps_double = 1.0,
nol_double = 1.0,
nol_double_vspom = 1.0;

do //Вычисление машинного эпсилона типа float
{
eps_float_vspom = eps_float_vspom/2;
eps_float = eps_float_vspom + 1;
}while (eps_float>1);
eps_float = eps_float_vspom*2;

do //Вычисление машинного эпсилона типа double
{
eps_double_vspom = eps_double_vspom/2;
eps_double = eps_double_vspom + 1;
}while (eps_double>1);
eps_double = eps_double_vspom*2;

do //Вычисление машинного нуля типа float
{
nol_float_vspom = nol_float;
nol_float = nol_float/2;
}while (nol_float>0);
nol_float=nol_float_vspom;

do //Вычисление машинного нуля типа double
{
nol_double_vspom = nol_double;
nol_double = nol_double/2;
}while (nol_double>0);
nol_double=nol_double_vspom;

//вывод результатов расчета
printf("Machine epsilon FLOAT:\t%.30e\n", eps_float);
binary_print((unsigned char*)&eps_float, 4);

printf("Machine epsilon DOUBLE:\t%.30e\n", eps_double);
binary_print((unsigned char*)&eps_double, 8);

printf("Machine nul FLOAT:\t%.30e\n", nol_float);
binary_print((unsigned char*)&nol_float, 4);

printf("Machine nul DOUBLE:\t%.30e\n", nol_double);
binary_print((unsigned char*)&nol_double, 8);

getch();
return 0;
}[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
12.05.2013, 22:58
общий
Посмотрите ответ. Будут вопросы, задавайте...
Ваши предложения, как сделать второй вариант?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
14.05.2013, 00:00
общий
Я сам не знаю. Изменить названия переменных, функций, плюс сами функции немного изменить каким-то образом. Ну чтоб не было понятно что делал программу 1 человек
давно
Посетитель
7438
7205
14.05.2013, 01:03
общий
Прошу
[code h=200]#include <conio.h>
#include <stdio.h>

//подпрограмма вывода бит вещественного числа
//параметры: адрес в памяти числа и число двойных слов
//подпрограмма универсальная: работает как с float, так и с double
//тип данных задается количеством двойных слов: 1 - для float, 2 - для double
void dvoich_vyvod(void *pData, int dwordKol)
{
unsigned int *pDw = (unsigned int *)pData;
int i, j;
char bits[64]; //строка бит числа (максимально 64)
unsigned int mask; //маска бита
int pos_znak; //индекс бита знака
int kol_eksp; //число бит экспоненты
int kol_mant; //число бит мантиссы

printf("Dvoich:");

//сделаем строку бит, младший - первым
for(i=0; i<dwordKol; i++) //циклим по двойным словам
{
mask = 1;
for(j=0; j<32; j++) //цикл по битам
{
if (pDw[i] & mask) //проверяем очередной бит
bits[i*32+j] = '1';
else
bits[i*32+j] = '0';
mask<<=1; //маска следующего бита
}
}

//вывод бит числа, начиная со старшего
j = dwordKol * 32; //количество бит числа
for(i=j-1; i>=0; i--) //начинаем с конца
{
if (0x07==(i&0x07)) //выведем пробел перед очередной восьмеркой бит
printf(" ");
printf("%c", bits[i]); //выводим очередной бит, как символ
}
printf("\n");

//выводим битовые поля числа
if (dwordKol == 1) //float
{
pos_znak = 31; //позиция знака
kol_eksp = 8; //число бит экспоненты
kol_mant = 23; //число бит мантиссы
}
else //double
{
pos_znak = 63; //позиция знака
kol_eksp = 11; //число бит экспоненты
kol_mant = 52; //число бит мантиссы
}
printf("Znak (1):\t%c", bits[pos_znak]); //знак
printf("\nExponenta (%d):\t", kol_eksp); //экспонента
for(i=0; i<kol_eksp; i++)
printf("%c", bits[pos_znak-i-1]); //биты экспоненты
printf("\nMantissa (%d):\t", kol_mant); //мантисса
for(i=0; i<kol_mant; i++)
printf("%c", bits[kol_mant-i-1]); //биты мантиссы
printf("\n\n");
}

int main()
{
float eps_float_1 = 1.0,
eps_float = 1.0,
nol_float = 1.0,
nol_float_1 = 1.0;
double eps_double_1 = 1.0,
eps_double = 1.0,
nol_double = 1.0,
nol_double_1 = 1.0;

do{ //Вычисление машинного эпсилона для float

eps_float_1 = eps_float_1/2;
eps_float = eps_float_1 + 1;
}
while (eps_float>1);
eps_float = eps_float_1*2;

do{ //Вычисление машинного эпсилона для double
eps_double_1 = eps_double_1/2;
eps_double = eps_double_1 + 1;
}
while (eps_double>1);
eps_double = eps_double_1*2;

do{ //Вычисление машинного нуля для float
nol_float_1 = nol_float;
nol_float = nol_float/2;
}
while (nol_float>0);
nol_float=nol_float_1;

do{ //Вычисление машинного нуля для double
nol_double_1 = nol_double;
nol_double = nol_double/2;
}
while (nol_double>0);
nol_double=nol_double_1;

//результаты расчета
//машинный эпсилон float
printf("Machiniy epsilon FLOAT:\t%.30e\n", eps_float);
dvoich_vyvod(&eps_float, 1);

//машинный эпсилон double
printf("Machiniy epsilon DOUBLE:\t%.30e\n", eps_double);
dvoich_vyvod(&eps_double, 2);

//машинный ноль float
printf("Machiniy nol FLOAT:\t%.30e\n", nol_float);
dvoich_vyvod(&nol_float, 1);

//машинный ноль double
printf("Machiniy nol DOUBLE:\t%.30e\n", nol_double);
dvoich_vyvod(&nol_double, 2);

getch();
return 0;
}[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2013, 13:22
общий
Адресаты:

Последний вопросик, преподы бушуют) так всё правильно, и отлично
Какие можно сделать выводы по полученным результатам(фотография ниже)?
(может на основе определений(вообще что такое машинный нуль и эпсилон)
заранее спасибо
Прикрепленные файлы:
7db45bc492e8a67be955e4786fe1481e.JPG
давно
Посетитель
7438
7205
24.05.2013, 13:42
общий
Преподаватели не "бушуют", а хотят увидеть у вас понимания происходящего...
Потому и задают дополнительные вопросы... Раз вы плаваете, значит работа списана...
С ответом на поставленный вопрос давайте разбираться вместе... Для начала, приведите определения машинного нуля и эпсилона...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2013, 14:09
общий
Адресаты:

я согласен
давайте разбираться

Машинный нуль - это число, меньше которого невозможно задавать точность для любого алгоритма, возвращающего вещественные числа.

Машинной эпсилон называется наименьшее положительное число ε такое, что 1+E (не)=1
давно
Посетитель
7438
7205
24.05.2013, 14:14
общий
Правильно.
Теперь скажите, что думаете Вы о полученном результате?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2013, 14:35
общий
что то однозначное я не могу сказать о полученном результате
следуя определениям можно сказать, что мы получили(эпсилон) наименьшее положительное значение, при прибавлении к которому 1, оно отлично от 1
и для для чисел а и b, выполняется отношение 1< a/b < 1+e , то машина эти числа не различает
а машинный нуль мы получили число, меньше которого точность задавать нельзя
давно
Посетитель
7438
7205
24.05.2013, 14:45
общий
Правильно. Преподавателям такой ответ не понравился, что ли?
Еще можно добавить, что чем выше разрядность числа, то и величины меньше...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2013, 14:49
общий
хотят конкретики
давно
Посетитель
7438
7205
24.05.2013, 14:54
общий
Сейчас я занят... Есть предложение продолжить попозже, вечерком, можно по ICQ. Мой ID в регкарте...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2013, 15:08
общий
вечерком к сожалению никак...
давно
Посетитель
7438
7205
24.05.2013, 15:12
общий
А я сейчас очень занят... Работа... Может, часиков через 3...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
24.05.2013, 17:13
общий
24.05.2013, 17:23
С учетом
Цитата: 397042
хотят конкретики


При выводе результата у Вас указаны количество бит выделяемое на вещественное число(знак, мантиса и экспонента).
Были проверены два вещественных типа double и float. По результатам видно, что чем больше бит отводится на мантису и экспоненту, то тем выше точность и тем меньшими числами можно оперировать.
Ниже приведены форматы машинного представления чисел:

Самые распространенные 32-ух и 64-ех битные варианты, у Вас используются в программе и практически это всё что может предоставить Вам компилятор С.


При желании можно было бы использовать и сопроцессор, но его программирование выходит за рамки курса языка С

Цитата: Лысков Игорь Витальевич
Преподаватели не "бушуют", а хотят увидеть у вас понимания происходящего...

Обратите внимание на пример перевода вещественного числа в машинный формат.
Практически он ничем не отличается от перевода в двоичную систему, только вес каждого бита в мантисе 1/(2 в степени n) зеркален относительно нуля. В экспоненте учитывается количество пропущенных нулевых бит до первой единицы(её отбрасывают, тем самым увеличивая точность полученого числа).

Всё, что Вам уже сказали Вы должны при докладе разбавить ещё и ручным переводом какого либо числа в машинный формат. Думаю, что после этого "им цеплятся будет стыдно".
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа