Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Прокомментируйте код, пожалуйста


Автор: xTr1m 29.3.2013, 11:58
Доброго времени суток. Решил отправить тестовое задание в яндекс, для собственной проверки. Задания вроде были не очень сложные, но получил отказ. Если можно, то хотел бы отдать кому-нибудь код "на проверку", чтобы сказали, что не так. Сюда, наверное, выкладывать не буду, могу отослать на почту или в личку. Заранее спасибо.

Автор: Alca 29.3.2013, 13:23
Чего? выкладывай

Автор: xTr1m 29.3.2013, 13:37
Ладно, прикреплю как файл

Автор: Guinness 29.3.2013, 14:12
Второе задание, я думаю они хотели примерно этого. Или если QString как контейнер не катит, то запихивать в массив char.
Код

#include <QCoreApplication>

#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    const quint32 mask = 0xFF;

    quint32 ip = 0x12AAEA3F;
    quint32 val = 0;
    QString ip_address;

    for(int i = 3; i >= 0; i--){
        val = (ip >> i*8) & mask;
        ip_address.append(QString("%1%2").arg(val).arg(i==0 ? "" : "."));
    }

    qDebug() << ip_address;

    
    return a.exec();
}

Автор: Alca 29.3.2013, 14:35
xTr1m, это, что все задания, не верю

Автор: xTr1m 29.3.2013, 14:38
там был еще один вопрос про скорость алгоритмов и на многопоточность. можно глянуть http://company.yandex.ru/job/vacancies/dev_browser.xml
это, как я понимаю, первый уровень отсева

Автор: bsa 29.3.2013, 14:47
xTr1m, и не удивительно, что тебя послали. Кому нужен оторванный от жизни школьник?
Функция main() должна возвращать int.
хидер "conio.h" нестандартен.
Тебя просили целое число преобразовать в строку, а ты что сделал?
Имхо, я бы это задание выполнил так:
Код
#include <iostream>

int main()
{
   unsigned int ip = 0x12345678;
   for(int i = 24; i >= 0; i -= 8) {
      std::cout << ((ip >> i) & 0xff);
      if (i > 0)
         std::cout << '.';
   }
   return 0;
}


Цитата(xTr1m @  29.3.2013,  15:38 Найти цитируемый пост)
там был еще один вопрос про скорость алгоритмов и на многопоточность. можно глянуть тут
это, как я понимаю, первый уровень отсева 
set, multiset (в т.ч. и сортированные - сортированы по умолчанию) и сортированные vector и deque.

А в примере на многопоточность есть как минимум две проблемы: когда Add лочит doubles, а Find(int) к этому времени уже залочил integers, затем Find может попытаться захватить doubles, но не выходит и ждет другой поток, а другой поток ждет освобождения integers - deadlock. Вообще ситуация с захватом двух мьютексов очень сложная и требует очень большой аккуратности и максимального ограничения областей захвата. В данном случае, лучше лочить не одновременно, а по очереди (что в find, что в add). Вторая проблема связана с сравнением чисел с плавающей точкой. Очень часто операция сравнения (operator==) может банально не работать. Поэтому для действительных чисел лучше использовать неточное сравнение ( abs(a - b) < eps ).

Автор: volatile 29.3.2013, 23:24
Код

// Перепишите код, устранив имеющиеся в нём проблемы, но не изменяя функцию main
class Foo {
 public:
  Foo(int j) { i = new int[j]; }
  ~Foo() { delete i; }

 private:
  int* i;
};

class Bar: Foo {
 public:
  Bar(int j) { i = new char[j]; }
  ~Bar() { delete i; }

 private:
  char* i;
};

void main() {
  Foo* f = new Foo(100);
  Foo* b = new Bar(200);
  *f = *b;
  delete f;
  delete b;
}

Ну вот кто это составляет такие заданя. Тут надо по крайней мере написать что они вообще хотели.
Если исходить из того, что дано, тогдаа члены i вообще нужно удалить. Доступа к ним нет, а сам класс с ними ничего не делает.
А фантазировать, на тему, что с ними хотел делать автор, это из области парапсихологии.
Так что вот так будет правильней:

Код

struct Foo {
  Foo(int) {}
};

struct Bar: Foo {
  Bar(int) : Foo (42) {}
};

void main() {
  Foo* f = new Foo(100);
  Foo* b = new Bar(200);
  *f = *b;
  delete f;
  delete b;
}

По крайней мере здесь все правильно, и интерфейс для пользователя, не изменицца.
(т.е. там где работал исходный код, там-же точно с таким эффектом будет работать и этот.
Только без путаницы и оверхедов.

Автор: noize 1.4.2013, 08:51
Цитата

Вторая проблема связана с сравнением чисел с плавающей точкой. Очень часто операция сравнения (operator==) может банально не работать

не раскажете подробнее о данной проблеме? 

Автор: Crafty 1.4.2013, 13:31
Цитата(noize @  1.4.2013,  08:51 Найти цитируемый пост)
не раскажете подробнее о данной проблеме?  

Проблема в том, что числа с плавающей точкой нельзя представить точно.
Код

#include <iostream>
#include <iomanip>

int main()
{
   double x = 1.0;
   double y = 0.0;
   for (int i = 0; i != 10; ++i)
   {
      std::cout  << std::setprecision(25) << y  << std::endl;
      y += 0.1;
   }
   if (y == x)
      std::cout << y << " == " << x << std::endl;
   std::cout << std::setprecision(25) << y << " != " << x << std::endl;
}


Код

stdout:
0
0.1000000000000000055511151
0.2000000000000000111022302
0.300000000000000044408921
0.4000000000000000222044605
0.5
0.5999999999999999777955395
0.699999999999999955591079
0.7999999999999999333866185
0.899999999999999911182158
0.9999999999999998889776975 != 1


Добавлено @ 13:34
Поэтому  обычно сравнивают вот так 
Код

#include <iostream>
#include <iomanip>

int main()
{
   double x = 1.0;
   double y = 0.0;
   for (int i = 0; i != 10; ++i)
   {
      y += 0.1;
   }
   double epsilon = 0.00001;
   if (std::abs(x - y) <= epsilon)
      std::cout << std::setprecision(25) << y << " == " << x << std::endl;
}

Автор: Guinness 1.4.2013, 13:44
Хм, я обычно сравниваю так:
Код

if(abs(a-b) < eps * max(a,b)){
    std::cout << "equal" << std::endl;
}

Автор: noize 1.4.2013, 14:02
Crafty
1. это справедливо и для float ?
2. В языке C действует такое же ограничение?

Автор: Crafty 1.4.2013, 14:05
Цитата(Guinness @  1.4.2013,  13:44 Найти цитируемый пост)
Хм, я обычно сравниваю так:

Зачем так много действий в условии и max и умножение
Попробуйте сравнить допустим 1.0 и 1.1 при эпислон 0.0001, в твоем случае он считает что они равны, что не верно

Добавлено @ 14:06
noize, на всех языках ИМХО одно и тоже что паскаль, что си, что питон. Тут дело не в языке программирования ,а в том как представлены числа с плавающей точкой на самой машине.

Добавлено @ 14:06
Цитата(noize @  1.4.2013,  14:02 Найти цитируемый пост)
1. это справедливо и для float ?

да

Автор: Guinness 1.4.2013, 14:37
Цитата(Crafty @  1.4.2013,  14:05 Найти цитируемый пост)
Зачем так много действий в условии и max и умножениеПопробуйте сравнить допустим 1.0 и 1.1 при эпислон 0.0001, в твоем случае он считает что они равны, что не верно


Разве?
(1.1 - 1.0 = 0.1) < 1.1 * 0.00001
Вроде как неравенство не проходит в данном случае, и числа неравны.

Собственно, делается это, для того чтобы сравнивать числа любых размеров. К примеру:
a = 0.008
b = 0.00701
eps = 0.001

abs(a-b) < max(a,b) * eps => 0.00099 < 0.008*0.001

Соотвественно, данные цифры не равны, что вполне логично. Т.к. различия у них в первой же значащей цифре.

И другой пример
a = 1.008
b = 1.00701
eps = 0.001

abs(a-b) < max(a,b) * eps => 0.00099 < 1.008*0.001

А тут цисла равны. Что, как мне кажется, правильно. В Вашем же случае, нужно постоянно менять эпсилон, чтобы понимать в каком знаке Вы хотите совпадения.

Автор: noize 1.4.2013, 14:40
Crafty, а как же утверждение о том, что стандарт языка гарантирует 6 цифр после мантиссы для float и n-ое количество цифр для double? 
Вот такая программка
Код

#include <iostream>

int main()
{
    using namespace std;

    float a = 0.000001;
    float b = 0.000002;
    cout << "a = " << a << "; b = " << b << endl;
    if (a == b) {
        cout << "a равняется b" << endl;
    } else if (b > a) {
        std::cout << "b больше a" << std::endl;
    }

    double c = 0.0000001;
    double d = 0.0000001;
    double e = 0.0000002;
    cout << "c = " << c << "; d = " << d << "; e = " << e << endl;
    if (c == d) {
        cout << "c равняется d" << endl;
    } else {
        cout << "c не равняется d" << endl;
    }
    if (c == e) {
        cout << "c равняется e" << endl;
    } else if (e > c) {
        cout << "e больше c" << endl;
    }

    return 0;
}

выдаёт вот такой результат:
Код

a = 1e-06; b = 2e-06
b больше a
c = 1e-07; d = 1e-07; e = 2e-07
c равняется d
e больше c

Автор: Crafty 1.4.2013, 14:41
Цитата(Guinness @  1.4.2013,  14:37 Найти цитируемый пост)
Разве?

http://liveworkspace.org/code/2JEbmD$6

Добавлено через 4 минуты и 27 секунд
Цитата(Guinness @  1.4.2013,  14:37 Найти цитируемый пост)
 В Вашем же случае, нужно постоянно менять эпсилон, чтобы понимать в каком знаке Вы хотите совпадения.

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

Автор: borisbn 1.4.2013, 14:48
Цитата(noize @  1.4.2013,  14:02 Найти цитируемый пост)
это справедливо и для float ?

в ещё бОльшей степени, чем для double.
Дело в том, что числа с плавающей точкой хранятся в компьютере след.образом:
user posted image
где fraction - это доля числа от 0 до 1 ( 52 нуля - это 0, 52 единицы - это 1, единица и 51 нуль - это примерно 0,5).
Минимальное расстояние между двумя числами 2^-52. Представь себе шкалу, с делениями 0, 2^-52, 2*2^-52, 3*2^-52 и т.д.
Если число, записанное в привычной тебе (и мне)) десятичной системе (например 0,1), попытаться положить на эту шкалу, то оно ляжет между двумя делениями (за исключением случаев точного попадания). При разборе такого кода:
Код
double x = 0.1;

компилятор "кладёт" это число на шкалу, затем берёт ближайшее значение из шкалы и записывает его в x. Т.о. в x помещается не 0,1, а ближайшее к нему (0.1000000000000000055511151).
Фух... я выдохся ))

Добавлено через 2 минуты и 50 секунд
Вот - http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8

Автор: Guinness 1.4.2013, 14:53
Цитата(Crafty @  1.4.2013,  14:41 Найти цитируемый пост)
Цитата(Guinness @  1.4.2013,  14:37 )Разве?http://liveworkspace.orgДобавлено через 4 минуты и 27 секундЦитата(Guinness @  1.4.2013,  14:37 ) В Вашем же случае, нужно постоянно менять эпсилон, чтобы понимать в каком знаке Вы хотите совпадения.Эпсилон это всего лишь точность с которой ты хочешь сравнивать числа, и не надо ничего менять.


Пардон, нужно fabs использовать. http://liveworkspace.org/code/2JEbmD$8

По поводу, не надо ничего менять. Я не согласен. Потому что, если вы ещё раз посмотрите пример, который я привел, то поймете, что в случае с Вашим использщованием эпсилон, сравнение некорректно.

Автор: Crafty 1.4.2013, 15:11
Цитата(Guinness @  1.4.2013,  14:53 Найти цитируемый пост)
По поводу, не надо ничего менять. Я не согласен. Потому что, если вы ещё раз посмотрите пример, который я привел, то поймете, что в случае с Вашим использщованием эпсилон, сравнение некорректно. 

Почему некорректно, сама идея в эпсилоне в том, что мы точно знаем какую точность нам надо учитывать, допустим эпсилон равен 0.0001 то мы уверены, что разница в числе не должна быть больше чем 0.0001 иначе они не равны.
Эпсилон всегда можно сделать достаточно маленьким.

Автор: Guinness 1.4.2013, 15:16
Цитата(Crafty @  1.4.2013,  15:11 Найти цитируемый пост)
Почему некорректно, сама идея в эпсилоне в том, что мы точно знаем какую точность нам надо учитывать, допустим эпсилон равен 0.0001 то мы уверены, что разница в числе не должна быть больше чем 0.0001 иначе они не равны.Эпсилон всегда можно сделать достаточно маленьким.


О том и речь. Что эпсилон Вам нужно будет менять в зависимости от размера сравниваемых чисел. Иначе получится такая петрушка:
Код

eps = 0.001
a = 1.002 и b = 1.0011 - равны
и
a = 0.002 и b = 0.0011 - также равны
-------------------------------------------
a = 1,00000001*10^10 и b=1.0*10^10 - неравны


Хотя, я понял Вашу мысль. Но я бы считал сравнение в приведенном выше примере - некорректным.

Автор: borisbn 1.4.2013, 15:49
Цитата(Guinness @  1.4.2013,  15:16 Найти цитируемый пост)
eps = 0.001
a = 1.002 и b = 1.0011 - равны
и
a = 0.002 и b = 0.0011 - также равны
-------------------------------------------
a = 1,00000001*10^10 и b=1.0*10^10 - неравны

ну... как бэ... да. а что смущает ?

Автор: Guinness 1.4.2013, 15:54
Цитата(borisbn @  1.4.2013,  15:49 Найти цитируемый пост)
ну... как бэ... да. а что смущает ?


В зависимости от того, что Вы хотите получить. Мне при сравнении чисел важно определенное количество знаков после первой значащей цифры, а не после запятой. И вариант, когда 0,002 = 0,0011, и при этом a = 1,00000001*10^10 и b=1.0*10^10, которые намного ближе друг к другу по значению - неравны, я считаю неприемлимым.

Собственно, главная проблема в том, что при сравнении нужно знать размер чисел, которые мы сравниваем.

Автор: fish9370 1.4.2013, 16:52
Цитата(noize @  1.4.2013,  14:40 Найти цитируемый пост)
а как же утверждение о том, что стандарт языка гарантирует 6 цифр после мантиссы для float и n-ое количество цифр для double? 


постараюсь расшифровать, то что пытаются тебе тут донести

если ты возьмешь и сделаешь так:

Код

double c = 0.0000001;
double d = 0.0000001;
if (c == f)
      printf("c & d are equal\n");


естественно, эти два числа будут равны, это у тебя по условию (ты сам туда записал два одинаковых числа)

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

PS. спор возникший, следует закрывать, вы оба правы, только вы вычисляете разные вещи..

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)