Некорректное округление сопроцессором

Discussion in 'WASM.BEGINNERS' started by ABCetc, May 11, 2008.

  1. ABCetc

    ABCetc New Member

    Blog Posts:
    0
    Joined:
    May 1, 2008
    Messages:
    9
    Доброго времени суток.
    Подскажите, пожалуйста, решение следующей проблемы.

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

    После вычисления логарифма (fyl2x), если не дай боже получилось целое число,
    он его, зараза, тоже "округляет". То есть получился результат 2, он из него сделает
    1, и т.п.

    Смотрел, сравнивал, разница при непосредственной загрузке и при получении числа
    в ходе вычисления только в выставленном флаге PE в слове состояния (status word).
    Но он, вроде, сигнализирует, а не влияет на вычисления. В любом случае, поменять его,
    возможности не представляется, да и, чувствую, лишняя это работа.
    Подскажите что-нибудь, а? Ведь, наверняка, решение простое.

    P.S. Пока-что отделался прибавлением ма-а-а-сюсенького числа, но это на время.
    Вычисления то нужны - точные.
     
  2. DEEP

    DEEP Андрей

    Blog Posts:
    0
    Joined:
    Apr 27, 2008
    Messages:
    491
    Location:
    г. Владимир
    дело в том, что число, получившееся в сопре, таки было равно не 2, а где-то стремлось к 1.(9) - и его если округлить к нулю, то и будет 1. Так что придётся на момент сохранения или прибавлять число, или округлять до ближайшего. А впрочем какая фиг разница - прибавлять-не прибавлять? Точные вычисления они на то и точные, что без округления... т.е. если округляешь - то или оставь это маленькое число, или поменяй флаги округления.
     
  3. HuXTUS

    HuXTUS New Member

    Blog Posts:
    0
    Joined:
    Jan 8, 2007
    Messages:
    240
    дык поставь режим округления - в сторону ближнего целого. Если не ошибаюсь, конечно
     
  4. ABCetc

    ABCetc New Member

    Blog Posts:
    0
    Joined:
    May 1, 2008
    Messages:
    9
    Округление нужно, чтобы получить правильный результат :)
    Нужно получить дробную часть числа.
    Отескается целая часть, поэтому округление должно быть в сторону нуля.
    ( 6.987 после округления к нулю = 6, в рез-те дробная часть = 0.987).


    Да, наверное так и оставлю - с прибавлением числа. Вот только...

    Пример. Я прибавляю, для примера, ДЕЛЬТА=0.001 (на самом деле меньше, но не суть важно).
    У меня число: 5.9996. Прибавляю ДЕЛЬТУ, получаю 6.0006. Округляю (получили 6), отнимаю от начального числа и получаю... Дробная часть числа 5.9996 равна (застрелиться и не встать!) -0.0004.

    Гадство...

    Взять ДЕЛЬТУ такой маленькой, чтобы сопроцессор ее не переплюнул? Так вроде у него в вычислениях вообще свой формат, по-моему разрядностью куда побольше, чем я могу задать в программе. Гадство...
     
  5. DEEP

    DEEP Андрей

    Blog Posts:
    0
    Joined:
    Apr 27, 2008
    Messages:
    491
    Location:
    г. Владимир
    Хм... А если всё сделать средствами CPU? Т.е. как известно, число типа флоат состоит из знака, мантиссы и экспоненты. Что если нам просто взять из числа экспоненту, и вычислив на её основе количество разрядов, относящихся к целой части числа, просто сдвинуть всю мантиссу с помощью SHL (Не забыв про знак, естестно), а потом отнять это же число от экспоненты? Правда, может получиться UNORM... ну а тут уж дальше BSR и всё такое - приведение к нормированному виду.
     
  6. Pavia

    Pavia Well-Known Member

    Blog Posts:
    0
    Joined:
    Jun 17, 2003
    Messages:
    2,409
    Location:
    Fryazino
    ABCetc
    Непонимаю чем тебе результат не устраивает? Все точно.
    Было 1,(9) округлили получили целую 1 вычли дробную 0,(9) И что это на алгоритм повлияет? Помойму нет.
     
  7. ABCetc

    ABCetc New Member

    Blog Posts:
    0
    Joined:
    May 1, 2008
    Messages:
    9
    2 Pavia

    Мне целая часть тоже нужна. Правильная.
    В том-то и фокус, что с 1.9 это прокатывает, а с целыми числами- нет.
    Еще раз повторю: после вычисления логарифма он "округляет" целые числа к нулю,
    то есть из 2 (нормальное такое 2 = 2.00000...) он делает 1.
    Дробную часть то он правильно найдет, спору нет.

    2 DEEP

    А-а-а-а! Нет! Не хочу... Неужто придется...
     
  8. leo

    leo Active Member

    Blog Posts:
    0
    Joined:
    Aug 4, 2004
    Messages:
    2,542
    Location:
    Russia
    ABCetc
    Не говори ерунды. Ты небось свое "нормальное такое" число в отладчике смотришь с огруглением до double, а в самом процессоре оно сидит в extended как 1.(9). Если сначала выгрузить число в double или single с обычным огруглением к ближайшему (RC = 00b), а затем загрузить заново и сделать frndint с округлением к нулю (RC = 11b), то все должно быть нормально
     
  9. ABCetc

    ABCetc New Member

    Blog Posts:
    0
    Joined:
    May 1, 2008
    Messages:
    9
    2 leo
    о... попробуем.

    Кстати, а логарифм по основанию 10 из 1000 - это в сопроцессоре будет 2.(9)?
    Если да - то нафиг такой сопроцессор нужен.
     
  10. God_Father

    God_Father New Member

    Blog Posts:
    0
    Joined:
    Aug 5, 2007
    Messages:
    99
    Народ может вы пользуетесь отладчиком olly с антиотладочными плугами?
    у меня с сопроцессором глюк из-за них был.
    Пока не удалил все.
    Пришлось 2 olly иметь, одну для программирования, одну для кряка.
     
  11. leo

    leo Active Member

    Blog Posts:
    0
    Joined:
    Aug 4, 2004
    Messages:
    2,542
    Location:
    Russia
    ABCetc
    Ну ты "ваще".. Во-первых, сопроцессор считает только log2, а логи по другим основаниям получаются делением на соотв.константу log2(10) и т.п. И сам log2 считается приближенно путем разложения в ряд (за искл.тривиальных случаев x=2^n), и константы являются иррациональными и заданы приближенно до 64 бит, и соотв-но при делении\умножении осуществляется округление до 64 бит мантиссы. Откуда тут возьмется "точное" значение ? В любом случае за счет ограниченного числа разрядов и округления младшего бита может получиться разница в +-2^(-63).
    Поэтому не стоит уподобляться плохим танцорам, которым вечно что-то мешает, а просто зарубить себе на носу, что при фпу-вычислениях нужно учитывать возможность потери точности в младших разрядах. И соответсвенно в зависимости от задачи либо "мириться" с этой неточностью, либо округлять итоговые значения до меньшего числа разрядов (double или single) - при этом мизерные ошибки исчезают и вместо 2.(9) получается 3.0