Прокомментируйте код, пожалуйста

 
0
 
C++
ava
xTr1m | 29.03.2013, 12:58
Доброго времени суток. Решил отправить тестовое задание в яндекс, для собственной проверки. Задания вроде были не очень сложные, но получил отказ. Если можно, то хотел бы отдать кому-нибудь код "на проверку", чтобы сказали, что не так. Сюда, наверное, выкладывать не буду, могу отослать на почту или в личку. Заранее спасибо.
c++
Ответы (22)
ava
Alca | 29.03.2013, 13:23 #
Чего? выкладывай
ava
xTr1m | 29.03.2013, 13:37 #
Ладно, прикреплю как файл
ava
Guinness | 29.03.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();
}
ava
Alca | 29.03.2013, 14:35 #
xTr1m, это, что все задания, не верю
ava
xTr1m | 29.03.2013, 14:38 #
там был еще один вопрос про скорость алгоритмов и на многопоточность. можно глянуть тут
это, как я понимаю, первый уровень отсева
ava
bsa | 29.03.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;
}
ava
volatile | 29.03.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) {}
};

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

По крайней мере здесь все правильно, и интерфейс для пользователя, не изменицца.
(т.е. там где работал исходный код, там-же точно с таким эффектом будет работать и этот.
Только без путаницы и оверхедов.
ava
noize | 01.04.2013, 08:51 #
Цитата


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


не раскажете подробнее о данной проблеме? 
ava
Crafty | 01.04.2013, 13:31 #
Цитата (noize @  1.4.2013,  08:51 findReferencedText)
не раскажете подробнее о данной проблеме?  

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

#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
ava
Guinness | 01.04.2013, 13:44 #
Хм, я обычно сравниваю так:

if(abs(a-b) < eps * max(a,b)){
    std::cout << "equal" << std::endl;
}
ava
noize | 01.04.2013, 14:02 #
Crafty, это справедливо и для float ?
ava
Crafty | 01.04.2013, 14:05 #
Цитата (Guinness @  1.4.2013,  13:44 findReferencedText)
Хм, я обычно сравниваю так:

Зачем так много действий в условии и max и умножение
Попробуйте сравнить допустим 1.0 и 1.1 при эпислон 0.0001, в твоем случае он считает что они равны, что не верно
ava
Guinness | 01.04.2013, 14:37 #
Цитата (Crafty @  1.4.2013,  14:05 findReferencedText)
Зачем так много действий в условии и 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

А тут цисла равны. Что, как мне кажется, правильно. В Вашем же случае, нужно постоянно менять эпсилон, чтобы понимать в каком знаке Вы хотите совпадения.
ava
noize | 01.04.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
ava
Crafty | 01.04.2013, 14:41 #
Цитата (Guinness @  1.4.2013,  14:37 findReferencedText)
Разве?

http://liveworkspace.org
ava
borisbn | 01.04.2013, 14:48 #
Цитата (noize @  1.4.2013,  14:02 findReferencedText)
это справедливо и для 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).
Фух... я выдохся ))
ava
Guinness | 01.04.2013, 14:53 #
Цитата (Crafty @  1.4.2013,  14:41 findReferencedText)
Цитата(Guinness @  1.4.2013,  14:37 )Разве?http://liveworkspace.orgДобавлено через 4 минуты и 27 секундЦитата(Guinness @  1.4.2013,  14:37 ) В Вашем же случае, нужно постоянно менять эпсилон, чтобы понимать в каком знаке Вы хотите совпадения.Эпсилон это всего лишь точность с которой ты хочешь сравнивать числа, и не надо ничего менять.


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

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

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


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

eps = 0.001
a = 1.002 и b = 1.0011 - равны
и
a = 0.002 и b = 0.0011 - также равны
ava
borisbn | 01.04.2013, 15:49 #
Цитата (Guinness @  1.4.2013,  15:16 findReferencedText)
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 - неравны

ну... как бэ... да. а что смущает ?
ava
Guinness | 01.04.2013, 15:54 #
Цитата (borisbn @  1.4.2013,  15:49 findReferencedText)
ну... как бэ... да. а что смущает ?


В зависимости от того, что Вы хотите получить. Мне при сравнении чисел важно определенное количество знаков после первой значащей цифры, а не после запятой. И вариант, когда 0,002 = 0,0011, и при этом a = 1,00000001*10^10 и b=1.0*10^10, которые намного ближе друг к другу по значению - неравны, я считаю неприемлимым.
ava
fish9370 | 01.04.2013, 16:52 #
Цитата (noize @  1.4.2013,  14:40 findReferencedText)
а как же утверждение о том, что стандарт языка гарантирует 6 цифр после мантиссы для float и n-ое количество цифр для double? 


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

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


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


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

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

PS. спор возникший, следует закрывать, вы оба правы, только вы вычисляете разные вещи..
Зарегистрируйтесь или войдите, чтобы написать.
Фирма дня
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Участники
  xTr1m ava  bsa   Alca ava  fish9370 ava  Crafty   Guinness ava  borisbn   noize   volatile
advanced
Отправить