2014-09-18 9 views
12

Работы над заданием для класса, я натолкнулся на это (обратите внимание условной петли)C++, как представляется, нарушает свойство сложения

// This one works. 
for (int k = 0; k + negwords[j].length() < comments[i].length(); k++) { 
    if (comments[i].substr(k, negwords[j].length()) == negwords[j]) { 
     negativeScore++; 
    } 
} 
//*/ 

/*/ This one doesn't: It fails with an out-of-bounds index. 
for (int k = 0; k < comments[i].length() - negwords[j].length(); k++) { 
    if (comments[i].substr(k, negwords[j].length()) == negwords[j]) { 
     negativeScore++; 
    } 
} 
//*/ 

Почему это, что первые из них работает, но второй один Безразлично» т? Это что-то о порядке операций, bool-принуждении к int, операторной ассоциативности или OBOE?

+10

Является ли 'length()' возвратом неподписанного типа? –

+1

не должно быть k + comments [i] .length() cyan

+0

@cyan: Нет, если вы вычитаете 'negwords [i] .length()' с обеих сторон первого условия цикла, вы получаете второе. –

ответ

33

Если либо negwords[j].length() или comments[i].length() вернуть неподписанный целочисленный тип по крайней мере, столь же большой, как unsigned int, то k будет поощряться к тому же без знака типа и правила модульного добавления будут применяться.

В качестве примера это означает, что 1 < 2 - 3 верно, потому что 2 - 3 обтекает модульную арифметику, становясь очень большим числом.

Если вы заинтересованы, такое поведение указано в разделе 3.9.1 стандарта, который включает в себя правило:

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

И сноска в отношении последствий:

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


Математики знают этот тип арифметики как алгебра полей Галуа . В C++ он используется для неподписанных интегральных типов. Другие типы не используют модульную арифметику, но они также не используют обычную арифметику средней школы (формально, - алгебра действительных чисел), потому что для нормальной арифметики требуется плотный несчетный набор чисел, а - компьютер конечного размер не может представлять элементы бесконечного множества.

Благодаря Оливеру за то, что я указал на свою ошибку. GF (2)^n управляет поразрядными операциями и целым рядом других общих вычислений, выполненных в компьютерном программном обеспечении, таких как CRC. Но он не описывает беззначную арифметику более 1 бит, так как многочлены на полях Галуа не «переносятся».

+4

@Cyber: Нет, нижний поток 'DBL_MIN/2.0 * 2.0' равен нулю. Это круто. –

+0

К сожалению, моя ошибка. – CoryKramer

Смежные вопросы