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

 
0
 
C++
ava
xTr1m | 29.03.2013, 12:58
Доброго времени суток. Решил отправить тестовое задание в яндекс, для собственной проверки. Задания вроде были не очень сложные, но получил отказ. Если можно, то хотел бы отдать кому-нибудь код "на проверку", чтобы сказали, что не так. Сюда, наверное, выкладывать не буду, могу отослать на почту или в личку. Заранее спасибо.
c++
Kommentare (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. спор возникший, следует закрывать, вы оба правы, только вы вычисляете разные вещи..
Registrieren Sie sich oder melden Sie sich an, um schreiben zu können.
Unternehmen des Tages
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Mitwirkende
  xTr1m ava  bsa   Alca ava  fish9370 ava  Crafty   Guinness ava  borisbn   noize   volatile
advanced
Absenden