| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > как получить целую часть веществ. числа |
| Автор: Frekenbok 6.1.2007, 14:35 | ||
| Привет всем! Вот проблемка возникла на пустом месте... Помогите, пожалуйста. Есть у меня переменная num типа double. Мне нужно получить целую часть числа или округлить "вниз". Вроде бы для этого существует функция floor, что меня очень радовало. Но на деле оказалось, что если num=1.0, то floor(num)=0.0, а мне нужно 1.0! Был у меня и другой вариант: извлечь целую и дробную части fract=modf(num, &intnum), но в этом случае если num=1.0, то получается fract=1.0, а intnum=0.0. Почему так? Если просто выводить printf("%.0lf",num), то он сам округляет, и получается не то, что нужно. На всякий случай поясню, как получаю num, может, это имеет значение, и где-то происходят какие-то округления и обрезания (в С ведь вечно так
Для grad ввожу значения 30, 45 и др. Нужно, чтобы для num=1.0 (1.1, 1.2,...,1.8,1.9) на экран вывелось 1, для num=2.0 (2.1, 2.2,...,2.8,2.9) вывелось 2 и т.п. (надеюсь, понятно P.S.Задачка на самом деле про то, как по углу часовой стрелки определить, сколько часов и минут на часах. |
| Автор: jonie 6.1.2007, 14:40 | ||
привести типы просто может?
ЗЫ: не проверял - под рукой компилятора нет. Но сколь память не изменяет... |
| Автор: WERITAS 6.1.2007, 14:42 |
| А другие функции округления не пробовали? round например? |
| Автор: ILAgent 6.1.2007, 15:03 | ||
Так можно, наверное:
|
| Автор: nickless 6.1.2007, 16:31 | ||||
floor() работает правильно, проблема в том, что ввиду двоичного представления чисел в компьютере num не может быть равен точно 1.0, только что-то вроде 0.9999999999954 (твой случай) или 1.000000000121, аналогично для modf() В принципе это не должно сильно мешать, но если в результате будут заметные ошибки, попробуй отлавливать такие места примерно так:
|
| Автор: Dov 6.1.2007, 17:10 | ||
|
| Автор: Dov 7.1.2007, 23:47 |
Что у тебя не получается, сказать можешь или это секрет. |
| Автор: Frekenbok 8.1.2007, 09:48 | ||
Dov, я понимаю, что выглядит все логично, взял int-ом обрезал и все. Но на практике не всегда действует. У меня Borland Turbo C++ 3.0. При значении num==1.0 (int)num получается равен 0. А все потому, что я не просто присваиваю num единицу, эта единица у меня получается в результате вычислений (см. первое сообщение), т.е. цитирую еще раз:
При использовании (int)num результат получается неверным, т.е. не тем, что мне надо. |
| Автор: W4FhLF 8.1.2007, 12:25 | ||
Borland Turbo C++ 3.0 поддерживает inline asm вставки? Тогда сделай что-то вроде этого:
|
| Автор: nickless 8.1.2007, 18:26 |
| W4FhLF, какая разница, это не от компилятора зависит, а от процессора |
| Автор: Daevaorn 8.1.2007, 18:28 |
от процессора зависит, поддерживает ли компилятор inline assembler? |
| Автор: nickless 8.1.2007, 18:32 | ||
Нет, тут весь топик идет речь о том, что floor(f) может быть равен 0.0, даже если f==1.0 |
| Автор: W4FhLF 8.1.2007, 18:52 | ||
Ты бы для начала постарался понять, что такое вещественное число в памяти(в этом тебе поможет моя статья: http://hunger.ru/articles/num), а потом посмотрел бы, что значит команда fist, но я не буду томить и скажу тебе, что эта команда округляет в большую сторону вещественное значение и записывает его в память. |
| Автор: nickless 8.1.2007, 19:08 | ||
Спасибо, я знаю. Между прочим fist округляет не в большую сторону, а в зависимости от fps status word, но и это не поможет округлить 0.9999999999 _вниз_ (человеку надо округлять в меньшую сторону) и получить 1 |
| Автор: Ln78 8.1.2007, 19:32 | ||
Мне кажется, в данной задаче суть в ошибках округления. Чтобы их уменьшить, можно воспользоваться тем, что в часах для угловой стрелки 360 угловых градусов соответствуют 12 временным часам или 720 временным минутам. Поэтому можно использовать такой вариант:
|
| Автор: W4FhLF 8.1.2007, 19:41 | ||||
Да, уточнил, я думал на флаг RC ориентируется только fistp. А как это округлить 0.9999999 в меньшую сторону и получить при этом 1? Что-то мне неясно. Кстати, вот пример округления до ближайшего целого, это поможет избавиться от погрешности с которой сопроцессор представляет числа в памяти:
На выходе в x имеем 1. |
| Автор: Mayk 8.1.2007, 20:15 | ||
1) можно тупо изобрести велосипед
2) достать нормальный компилятор. |
| Автор: Anikmar 9.1.2007, 19:55 |
| Можно так: floor(num+0.1); или floor (num+0.01) |
| Автор: Frekenbok 10.1.2007, 04:13 |
А если число будет 1.954187? Тогда floor(num+0.1) будет равно 2. А надо 1. |
| Автор: codelord 10.1.2007, 07:03 |
| Frekenbok, а вариант Mayk, чем не устраивает? |
| Автор: Frekenbok 10.1.2007, 07:34 |
Все-таки в 1 случае из 25 вывел неверно Можно ли просмотреть значения переменных С++ в дебаггере наподобие ассемблера? чтобы видно было, какое число получается в ячейке памяти? W4FhLF, кстати, твой вариант не сработал, надо как-то подгонять под мои данные, наверное. У меня double num вместо float f. Не знаю, имеет ли это значение, наверное, да. До программирования сопроцессора еще не дошло дело. Пока только процессор. Добавлено @ 07:36 А почему, кстати, в моем варианте число именно меньше 1 (0.99999999), а не больше (1.000000000024)? В скобках я к примеру указываю. |
| Автор: W4FhLF 10.1.2007, 08:10 | ||||||
Ну имеет конечно, double занимает 8 байт, а float 4. Так вот попробуй:
На выходе в x получаем 1. Что и требовалось доказать Добавлено @ 08:11
А оно почти всегда будет чуть меньше, кроме тех случаев, когда ты сохраняешь периодичную, с точки зрения двоичной системы, дробь(0.125 или 8.625 например). Это погрешность при переводе десятичных дробей в двоичные. |
| Автор: codelord 10.1.2007, 08:13 | ||||||
ну вот от меня еще вроде работает, надеюсь и у тебя тоже будет.
Добавлено @ 08:21
наведи каретку на переменную и ctrl + f5 по моему вроде так |
| Автор: Frekenbok 16.1.2007, 11:02 | ||
Тогда получается, что если у меня число 0.999999, то мне, наоборот, надо округлять "вверх"! А вот вариант codelord то, что надо. Спасибо. В Turbo C++ 3.0 не работает. Вообще, всем спасибо за помощь. Думаю, тему можно закрыть |
| Автор: Frekenbok 16.1.2007, 11:26 | ||
Кстати, очень хороший вариант. Только по условию задачи угол в радианах. Я ввожу в градусах, чтобы потом легче было сопоставить угол и время. Отсюда и вылезают всякие погрешности округления |
| Автор: xKrIvEdKox 31.5.2009, 02:01 |
| x:=round(x*100)/100; |
| Автор: Dmi3ev 1.6.2009, 00:59 |
| удалил... |