язык C в Linux: вопросы начального уровня

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Виктория
Писатель
Сообщения: 113
Зарегистрирован: 28 дек 2012, 14:05
Откуда: Самара
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Виктория » 12 ноя 2013, 17:21

Olej писал(а):
Виктория писал(а):
Если посмотреть на эту задачу совсем уж прагматично, то правильный ответ возможен с использованием объединения union и сравнения целых чисел. Хотя, как мне кажется, возможны и более элегантные решения...
Хотя бы так
1. А почему так?
Т.е., я понимаю, что вы хотите наблюдать полную побитовую идентичность...
А что происходит при вещественном сравнении?
Типа 1. + X == 1. + X / 2.
(я спрашиваю, потому что не знаю ответа... real-операции в x86 производятся в регистрах FPU - а операция сравнения?)
Хе! Если X / 2, это уже совсем другая задача :-)

На Ваш вопрос я тоже не знаю ответа. Посмотрю. Похоже, что операция сравнения тоже в FPU. А в книжку Форсайта мне заглядывать не хочется, зазорно. Я её в студенческом возрасте читала
Виктория писал(а):В компиляторе должны быть обработчики исключений по переполнению, потому что пример "на грани фола".

Код: Выделить всё

3. А это как?
(я не понял о чём это утверждение)
Потому что в Вашем цикле мы добегаем до переполнения, поэтому и 1+x становится равным 1+x/10 (и там, и там по единице).

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 12 ноя 2013, 17:55

Виктория писал(а): Хе! Если X / 2, это уже совсем другая задача :-)
Осторожно ;-) - там вещественное 2!
(2.0 даже чаще используется в таком контексте, 10.0 я использовал только для того, чтобы ускорить сходимость)
Виктория писал(а): Потому что в Вашем цикле мы добегаем до переполнения, поэтому и 1+x становится равным 1+x/10 (и там, и там по единице).
А в чём разница?
И в случае epsilon/10.0 и в случае epsilon/2.0 происходит экспоненциальное уменьшение значения epsilon (только с разной скоростью экспоненты), и смысл сравнения становится в том, что когда-то ;-) ( 1. + epsilon ) становится неотличимым от просто 1.
P.S. кстати, для большей понятности можно вместо критерия выхода и записать "неотличимость от 1" ... заодно и проще станет ;-)

Код: Выделить всё

do {} while ( 1. != 1. + ( X /= 2. ) );
Виктория писал(а): А в книжку Форсайта мне заглядывать не хочется, зазорно. Я её в студенческом возрасте читала
Я тоже в студенческие годы читал...
Но это мне совсем не мешает её регулярно ... раз дет в 10 ;-) ... с большим удовольствием полистать.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 12 ноя 2013, 18:04

Виктория писал(а): На Ваш вопрос я тоже не знаю ответа. Посмотрю. Похоже, что операция сравнения тоже в FPU.
Если операция выполняется FPU, то там, с большой степенью уверенности могу предполагать, сравнение производится не по признаку побитовой эквивалентности.

Да и если real-операции даже выполняются библиотечно (на процессоре, например, без FPU), вещественное сравнение должно выполняться сложнее побитовой эквивалентности, просто потому, что различные формы должны давать равные значения:
1.0 , 0.1e1, 10e-1, ... 0.99999...
Начиная с нормализации, если она, например, почему-то не была выполнена в завершение предыдущей операции.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 18 ноя 2013, 16:20

Виктория писал(а):
Olej писал(а): Но показать такие фрагменты-тексты - очень полезно: останется на уровне рефлексов, даже забыв почему это так: "никогда не сравнивать в if вещественные значения на равенство..." и др. т.д. и т.п.
:-? Боюсь, что без правильного ответа не запомнют
Ещё один очень интересный, хоть и частный вопрос - рекурсия.
Выразительная мощь рекурсивных решений - огромная.
Но без конкретного тыкания пальцем обучающийся никогда сам не обратит внимания на эту целую отдельную область методов.

Для простейшего "введения в предмет" нарисую "классику" ознакомления с рекурсией - вычисление факториала, но 3-мя разными способами:

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>

unsigned long long fact1( int n ) {
   unsigned long long f = 1;
   int i;
   for( i = 1; i <= n; i++ ) f *= i;
   return f;
}

unsigned long long fact2( int n ) {
   unsigned long long f = 1;
   while( n > 1 ) f *= n--;
   return f;
}

unsigned long long fact3( int n ) {
   return 0 == n || 1 == n ? 1 : n * fact3( n - 1 );
}

int main( int argc, char **argv, char **envp ) {
   int n, m, i;
   unsigned long long ( *funcs[] )( int ) = { 
      fact1, fact2, fact3
   };
   while( 1 ) {
      printf( "число: " );
      fflush( stdout );
      m = scanf( "%d", &n );
      if( m <= 0 ) {
         printf( "\n" );      
         break;
      }
      printf( "%d! => ", n );
      for( i = 0; i < sizeof( funcs ) / sizeof( funcs[ 0 ] ); i++ ) 
         printf( "%llu ,  ", funcs[ i ]( n ) ); 
      printf( "\n" );      
   }
   return 0;
}

- способ №1 тривиальный - это цикл перемножения снизу-вверх...
- способ №2 - это тот же цикл но сверху-вниз ... а включил я его потому, что он лишний раз иллюстрирует такую вещь, что скалярные параметры передаются по значению (своими копиями), и с ними можно в функции делать что угодно (дикрементировать) без побочных эффектов...
- способ №3 - это то, из-за чего это написано - рекурсивное вычисление ... и вместо "мудрить" всё уместилось в 1 оператор return ;-) :

Код: Выделить всё

olej@notebook:~/2013_WORK/AntonG/examples$ ./factorial
число: 3
3! => 6 ,  6 ,  6 ,
число: 4
4! => 24 ,  24 ,  24 ,
число: 5
5! => 120 ,  120 ,  120 ,
число: 10
10! => 3628800 ,  3628800 ,  3628800 ,
число: 20
20! => 2432902008176640000 ,  2432902008176640000 ,  2432902008176640000 ,
число:
^D
Вложения
factorial.c
(887 байт) 297 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 18 ноя 2013, 16:37

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

Классикой являются и рекурсивные алгоритмы элементарной сортировки ... только упор здесь нужно бы делать не на само запоминание быстрых алгоритмов, а на логику использования рекурсии в них.

Мне так кажется, что одна из лучших иллюстраций мощности рекурсии как вычислительного метода - это известная задача "ханойская башня":
- есть 3 штыря ...
- на которые нанизываются пирамидки из колец разного диаметра, на манер детских пирамидок ...
- перекладывать "за-раз" можно только 1-но верхнее кольцо с любого штыря на любой...
- при условии, что перекладывать можно только кольцо меньшего диаметра сверху на кольцо большего диаметра, но не наооборот;
- нужно пирамиду из N колец, лежащих на штыре №1, переместить по этим правилам на штырь №3 (№2 и №3 изначально пустые).

Попробуйте желающие решить эту задачу нерекурсивными методами!
(По преданию, эту задачу перекладывая колечки, решают тибетские монахи, и когда они её решат - тогда наступит конец света :-o .)

А вот рекурсивное решение:

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>

int nopr = 0;

void put( int from, int to ) {
   printf( "%d => %d,   ", from, to );
   if( 0 == ( ++nopr % 5 ) )
      printf( "\n" ); 
}

int temp( int from, int to ) {  // промежуточная позиция
   int i = 1;
   for( ; i <= 3; i++ )
      if( i != from && i != to )
         return i;
}

void move( int from, int to, int n ) {
   if( 1 == n ) put( from, to );
   else {
      move( from, temp( from, to ), n - 1 );
      put( from, to );
      move( temp( from, to ), to, n - 1 );
   }
}

int main( int argc, char **argv, char **envp ) {
   int n = 5;                 // число переносимых фишек
   if( argc > 1 && atoi( argv[ 1 ] ) != 0 )
      n = atoi( argv[ 1 ] );   
   printf( "размер пирамиды: n=%d\n", n ); 
   move( 1, 3, n );           // вот и всё решение!
   if( 0 != ( nopr % 5 ) )
      printf( "\n" ); 
   printf( "общее число перемещений %d\n", nopr ); 
   return 0;
}
Здесь всё решение делается 1-м оператором: move( 1, 3, n );
Но самое интересное здесь то, что я не знаю алгоритма решения задачи, сам алгоритм находится в процессе раскрутки рекурсивно сформулированной цели задачи!
Т.е.решение здесь формулируется так:
- если n=1 и перетаскивать нужно пирамидку только из 1-го кольца - то просто взять его и переложить: from -> to
- а вот если n!=1, тогда: ...
- переставить (а как? - а я не знаю как это сделать!) верхнюю пирамидку n-1 колец на промежуточный штырь (не from и не to) ...
- переместить оставшееся большой кольцо на to ...
- опять же, переместить n-1 пирамидку (см. выше) с промежуточного штыря на to ...
Вот и всё как просто! ;-)

Код: Выделить всё

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 2
размер пирамиды: n=2
1 => 2,   1 => 3,   2 => 3,   
общее число перемещений 3

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 3
размер пирамиды: n=3
1 => 3,   1 => 2,   3 => 2,   1 => 3,   2 => 1,   
2 => 3,   1 => 3,   
общее число перемещений 7

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 4
размер пирамиды: n=4
1 => 2,   1 => 3,   2 => 3,   1 => 2,   3 => 1,   
3 => 2,   1 => 2,   1 => 3,   2 => 3,   2 => 1,   
3 => 1,   2 => 3,   1 => 2,   1 => 3,   2 => 3,   
общее число перемещений 15

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 5
размер пирамиды: n=5
1 => 3,   1 => 2,   3 => 2,   1 => 3,   2 => 1,   
2 => 3,   1 => 3,   1 => 2,   3 => 2,   3 => 1,   
2 => 1,   3 => 2,   1 => 3,   1 => 2,   3 => 2,   
1 => 3,   2 => 1,   2 => 3,   1 => 3,   2 => 1,   
3 => 2,   3 => 1,   2 => 1,   2 => 3,   1 => 3,   
1 => 2,   3 => 2,   1 => 3,   2 => 1,   2 => 3,   
1 => 3,   
общее число перемещений 31

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 6
размер пирамиды: n=6
1 => 2,   1 => 3,   2 => 3,   1 => 2,   3 => 1,   
3 => 2,   1 => 2,   1 => 3,   2 => 3,   2 => 1,   
3 => 1,   2 => 3,   1 => 2,   1 => 3,   2 => 3,   
1 => 2,   3 => 1,   3 => 2,   1 => 2,   3 => 1,   
2 => 3,   2 => 1,   3 => 1,   3 => 2,   1 => 2,   
1 => 3,   2 => 3,   1 => 2,   3 => 1,   3 => 2,   
1 => 2,   1 => 3,   2 => 3,   2 => 1,   3 => 1,   
2 => 3,   1 => 2,   1 => 3,   2 => 3,   2 => 1,   
3 => 1,   3 => 2,   1 => 2,   3 => 1,   2 => 3,   
2 => 1,   3 => 1,   2 => 3,   1 => 2,   1 => 3,   
2 => 3,   1 => 2,   3 => 1,   3 => 2,   1 => 2,   
1 => 3,   2 => 3,   2 => 1,   3 => 1,   2 => 3,   
1 => 2,   1 => 3,   2 => 3,   
общее число перемещений 63

olej@notebook:~/2013_WORK/AntonG/hanoy$ ./hanoy 7
размер пирамиды: n=7
1 => 3,   1 => 2,   3 => 2,   1 => 3,   2 => 1,   
2 => 3,   1 => 3,   1 => 2,   3 => 2,   3 => 1,   
2 => 1,   3 => 2,   1 => 3,   1 => 2,   3 => 2,   
1 => 3,   2 => 1,   2 => 3,   1 => 3,   2 => 1,   
3 => 2,   3 => 1,   2 => 1,   2 => 3,   1 => 3,   
1 => 2,   3 => 2,   1 => 3,   2 => 1,   2 => 3,   
1 => 3,   1 => 2,   3 => 2,   3 => 1,   2 => 1,   
3 => 2,   1 => 3,   1 => 2,   3 => 2,   3 => 1,   
2 => 1,   2 => 3,   1 => 3,   2 => 1,   3 => 2,   
3 => 1,   2 => 1,   3 => 2,   1 => 3,   1 => 2,   
3 => 2,   1 => 3,   2 => 1,   2 => 3,   1 => 3,   
1 => 2,   3 => 2,   3 => 1,   2 => 1,   3 => 2,   
1 => 3,   1 => 2,   3 => 2,   1 => 3,   2 => 1,   
2 => 3,   1 => 3,   2 => 1,   3 => 2,   3 => 1,   
2 => 1,   2 => 3,   1 => 3,   1 => 2,   3 => 2,   
1 => 3,   2 => 1,   2 => 3,   1 => 3,   2 => 1,   
3 => 2,   3 => 1,   2 => 1,   3 => 2,   1 => 3,   
1 => 2,   3 => 2,   3 => 1,   2 => 1,   2 => 3,   
1 => 3,   2 => 1,   3 => 2,   3 => 1,   2 => 1,   
2 => 3,   1 => 3,   1 => 2,   3 => 2,   1 => 3,   
2 => 1,   2 => 3,   1 => 3,   1 => 2,   3 => 2,   
3 => 1,   2 => 1,   3 => 2,   1 => 3,   1 => 2,   
3 => 2,   1 => 3,   2 => 1,   2 => 3,   1 => 3,   
2 => 1,   3 => 2,   3 => 1,   2 => 1,   2 => 3,   
1 => 3,   1 => 2,   3 => 2,   1 => 3,   2 => 1,   
2 => 3,   1 => 3,   
общее число перемещений 127
Так что конец света - близок! :lol:
Вложения
hanoy.c
(1.1 КБ) 293 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 19 ноя 2013, 12:56

Olej писал(а):
Olej писал(а): Выразительная мощь рекурсивных решений - огромная.
В этом можете не сомневаться ;-) , это известно из теории алгоритмов ... но это не очевидно, и на это нужно обращать внимание.
Особенно это в совершенно практических задачах распознавания образов, оценивания гипотез, поиска оптимальных вариантов ... всегда, когда создаются динамические структуры данных: списки, деревья, графы...
Относительно "динамических" структур тоже есть ряд замечаний...
Динамическими (исходя из стереотипа) чаще всего называют структуры данных, в которых элементы данных (узлы) создаются и уничтожаются динамически, "по ходу", используя malloc()/free() (new/delete в C++).
Это не совсем верно (совсем неверно? ;-) ), потому что такие структуры данных совершенно легко могут быть определены и статически. Вот например:

Код: Выделить всё

#define LINKS 3
struct node {           // отдельный узел графа
   int num;
   struct node *ch[ LINKS ];
} graf[] = {            // направленный граф - пирамида
   { 1, { &graf[ 1 ], &graf[ 2 ], &graf[ 3 ] } },
   { 2, { &graf[ 0 ], &graf[ 2 ], &graf[ 3 ] } },
   { 3, { &graf[ 0 ], &graf[ 1 ], &graf[ 3 ] } },
   { 4, { &graf[ 0 ], &graf[ 1 ], &graf[ 2 ] } },
};
Это определён полносвязный направленный граф в виде 3D 3-х-гранной пирамиды.

Динамическими такие структуры являются не в силу динамичности её узлов (это дело 2-е), а в силу динамичности связей этих узлов, выраженных через ссылки. Поэтому куда точнее для таких структур будет название, иногда употребляемое, как "ссылочные структуры данных".

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 19 ноя 2013, 13:03

Olej писал(а): Это определён полносвязный направленный граф в виде 3D 3-х-гранной пирамиды.
А вот так может выглядеть рекурсивная процедура обходя всех связных маршрутов в таком графе ... и не только в таком, а в любом подобном, произвольно сложной топологии. Процедура исключает петлевые маршруты в графе. Программа может начать обход с произвольной вершины графа, и отыскивает все возможные маршруты (сделать такое не рекурсивно ... я даже не представляю какое это потребует сложности):

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LINKS 3
struct node {           // отдельный узел графа
   int num;
   struct node *ch[ LINKS ];
} graf[] = {            // направленный граф - пирамида
   { 1, { &graf[ 1 ], &graf[ 2 ], &graf[ 3 ] } },
   { 2, { &graf[ 0 ], &graf[ 2 ], &graf[ 3 ] } },
   { 3, { &graf[ 0 ], &graf[ 1 ], &graf[ 3 ] } }, 
   { 4, { &graf[ 0 ], &graf[ 1 ], &graf[ 2 ] } }, 
};
int size = sizeof( graf ) / sizeof( graf[ 0 ] );

struct list {           // список пройденных узлов
   struct node *ptr;
   struct list *next;
};

int length( struct list *plist ) {
   struct list *p = plist;
   int n = 1;
   while( ( p = p->next ) != NULL ) n++;
   return n;
}

int into( struct list *plist, struct node *ptr ) {
   struct list *p = plist;
   do {
      if( p->ptr == ptr ) return 1;
   } while( ( p = p->next ) != NULL );
   return 0;
}

void next( struct list *prev ) {
   int i, L = length( prev );
   if( L >= size ) return;  // страховка завершения
   for( i = 0; i < L - 2; i++ ) printf( "     " );
   if( i < L - 1 ) printf( "+--->" );
   printf( "%d\n", prev->ptr->num );
   struct node *curr = prev->ptr;
   for( i = 0; i < LINKS; i++ ) {
      if( NULL == curr->ch[ i ] || into( prev, curr->ch[ i ] ) ) continue;
      struct list nxt = { curr->ch[ i ], prev };
      next( &nxt );
   }
}

int main( int argc, char **argv, char **envp ) {
   int n, m;
   char msg[ 100 ] = "начальный узел [ ";
   for( m = 0; m < size; m++ )
      sprintf( msg + strlen( msg ), " %d%s ",
               ( graf + m )->num, ( m != size - 1 ? "," : " ]:" ) );
   while( 1 ) {
      printf( "%s", msg );
      fflush( stdout );
      m = scanf( "%d", &n );
      if( m <= 0 ) {
         if( m < 0 ) printf( "\n" );
         break;
      }
      for( m = 0; m < size; m++ )
         if( ( graf + m )->num == n ) break;
      if( m == size ) printf( "нет такого узла!\n" );
      else {
         struct list arg = { graf + m, NULL };
         next( &arg );
      }
   }
   return 0;
}
И выглядит это так:

Код: Выделить всё

olej@notebook:~/2013_WORK/AntonG/tasks$ ./graf
начальный узел [  1,  2,  3,  4 ]: 2
2
+--->1
     +--->3
     +--->4
+--->3
     +--->1
     +--->4
+--->4
     +--->1
     +--->3
начальный узел [  1,  2,  3,  4 ]: 4
4
+--->1
     +--->2
     +--->3
+--->2
     +--->1
     +--->3
+--->3
     +--->1
     +--->2
начальный узел [  1,  2,  3,  4 ]: ^D
P.S. Здесь (в коде) интересны 2 момента:
1. нет явного ограничения глубины рекурсии, просто при определённой глубине уже не порождаются новые рекурсивные вызовы (пустой цикл);
2. параметр next() - список переменной длины уже пройденных узлов графа, он создаётся/уничтожается без единого malloc/free - достаточно всего лишь локальных структур в стеках вызовов, завязанных в список.
Вложения
graf.c
(2.08 КБ) 284 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 19 ноя 2013, 14:41

Виктория писал(а): Мне не совсем понятно назначение тестов в преподавании программирования. Почему бы не использовать лишь задачи на "придумать алгоритм и реализовать его в программе"?
Виктория, вы правы ;-) .
Но то, о чём говорю я - это не тесты ... в понимании тестов, это просто "очень маленькие задачки"...
И в Makefile в текущем виде "тесты" (которые совсем "мелочёвка") собраны в список TEST, а "задачи" (которые покрупнее) - в список TASK:

Код: Выделить всё

TEST = type struct opera func string gccex 
TASK = hanoy factorial graf
Это и есть "придумать алгоритм и реализовать его в программе".
Вложения
examples.tgz
(11.17 КБ) 301 скачивание

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 19 ноя 2013, 17:11

Виктория писал(а): Мне не совсем понятно назначение тестов в преподавании программирования. Почему бы не использовать лишь задачи на "придумать алгоритм и реализовать его в программе"?
Набор проверочных тестов-программ для проверки (самопроверки) знания языка C: C Programming Puzzlers - 16 страниц тестовых программ.
Этот URL полезен тем, что а). там не совсем тривиальные примеры, типа x++ + ++y ;-) , б). там все примеры с ответами, так что это можно использовать для самоконтроля.

Аватара пользователя
Виктория
Писатель
Сообщения: 113
Зарегистрирован: 28 дек 2012, 14:05
Откуда: Самара
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Виктория » 19 ноя 2013, 18:22

Olej писал(а): Набор проверочных тестов-программ для проверки (самопроверки) знания языка C: C Programming Puzzlers - 16 страниц тестовых программ.
Этот URL полезен тем, что а). там не совсем тривиальные примеры, типа x++ + ++y ;-) , б). там все примеры с ответами, так что это можно использовать для самоконтроля.
Ага. По ссылке самые обычные тесты, для младших курсов
Виктория, вы правы .
Но то, о чём говорю я - это не тесты ... в понимании тестов, это просто "очень маленькие задачки"...
Маленькие задачи? Или задачи с некоторым припрятанным смыслом?
Мне сегодня совершенно случайно попалась статья про сравнение чисел типа float
Bruce Dawson. Comparing floating point numbers
В Компьютерре раньше статей на эту тему много было, типа как сейчас на habrahabre
Что нужно знать про арифметику с плавающей запятой (из песочницы)

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: FAST WebCrawler [Crawler] и 8 гостей