Ответ на данетку

В ходе обсуждения были даны ответы:
- остаток на счёте перед снятием не проверяется
- ошибка произошла при выполнении 3-й операции
- перед 3-й операцией на счёте $400
- в овердрафт не уходит (не может быть отрицательной суммы) ( - странно, что тогда происходит?)
- доллары с рублями не путает
- вместо отрицательной суммы 0 не подставляет
- других операций по счёту не было
- после 3-й операции происходило списание со счёта
- остаток - не отрицательное значение, не $0, не $400, не $300, не $500
- результат не зависит от архитектуры и выбранной СУБД
- ответ “близко” на “Записали отрицательное число в беззнаковую переменную”

Но правильный ответ так и не был получен.

– Ответ ————–

Код сервера приложений  (примерно такой):

{ остаток=остаток - сумма снятия;

if остаток < 0

then {сообщение об ошибке()}

else {выдать дньги;

сохранить новый остаток и операцию в базе данных}
}

Вроде бы никакого криминала нет. Проверка есть. Правда стоит она не до попытки совершения операции, а после. Все замечательно работает. Почти всегда.

Но есть такой прием, при котором с деньгами работают через целые переменные, храня в них центы. Счет исключительно дебетовый, почему бы не взять беззнаковое целое? Двухбайтовое для зарплатного счета маловато - максимальная сумма 655 долларов 35 центов, а четырехбайтовое в самый раз. Максимальная сумма - $42 949 672.95. Сорок два миллиона долларов - вполне достаточно. Но при выполнении кода отрицательного числа быть не может и проверка становится бессмысленной. Конечная сумма на счете: $42 949 672.95 - $100.00 = $42 949 572.95 Хорошая прибавка к старости.

Неаккуратное использование целочисленных переменных - широкий класс ошибок, встречающийся очень часто. Постпроверка также встречается довольно часто. Заметим, что по отдельности эти два момента не приводят к ошибке программы. Нужно, чтобы две небрежности встретились. Модель "швейцарского сыра” в действии.

Комментариев: 8

  1. xBsd написал:

    Ну как же так, я был очень близко

    >>используется беззнаковый тип?

    >>сумма денег на счету что-то типа uint.MaxValue - 100?

    ошибся на два порядка ))

  2. SALar написал:

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

    PS. Эти штуки лучше применять в обратном порядке: “Я знаю, что есть такой класс ошибок. Попробуем сделать тест на выявление.” Работает на “ура”.

  3. algo_dogs написал:

    Не очень понятно, откуда в целой переменной появились центы и соответственно разница на два порядка?
    Насколько я знаю при таком использовании целых, отдельно хранится scale, с помощью которого находится итоговое значение.

  4. algo_dogs написал:

    Понял, фактически в базу пишется не -100, а -10000.

  5. xBsd написал:

    Кстати а на каком языке писалось? Например в Java так ошибиться очень сложно ибо там по умолчанию нет беззнаковых типов.

  6. SALar написал:

    Это придуманный пример. На С такое можно написать.

  7. Llanie написал:

    Почему тогда так:
    >> сумма денег на счету что-то типа uint.MaxValue - 100?
    >Нет.

    Только из-за точности? Но тогда почему
    > > Записали отрицательное число в беззнаковую переменную.
    > > Например так: 4294967196
    > Близко.

    После первого ответа перестала крутить версию про переполнение.

    (В минус, кстати, даже исключительно дебетовый счёт может уйти, за счёт курсов и комиссий.)

  8. algo_dogs написал:

    >После первого ответа перестала крутить версию про переполнение.
    Проблема не в переполнении, а скорее неявном приведении типа.

Оставьте комментарий

Вы должны войти, чтобы оставить свой комментарий.