Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Преобразование вещественной части в целое 
:(
    Опции темы
feodorv
Дата 21.8.2013, 03:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(akizelokro @  20.8.2013,  21:26 Найти цитируемый пост)
Есть разница между 

Есть! Только я не понимаю, как умножая на 10 Вы собираетесь свести ldval к нулю:
Цитата(akizelokro @  20.8.2013,  21:26 Найти цитируемый пост)
while ( ldval != 0 )
{
              ldval *= 10;
              // взять целочисленную часть, образовавшуюся после умножения цифру и выдрать её в string
}

По идее, с нулём нужно сравнивать дробную часть ldval:
Код
#include <stdio.h>

int main( void )
{
  long double x = .45600001;

  printf( "." );
  while( x != 0 )
  {
    x *= 10;
    printf( "%c", (int) x + '0');
    x -= (int) x;
  }

  return 0;
}


На выходе получается что-то вроде
Цитата
.4560000099999999889632817939855158329010009765625


Цитата(akizelokro @  20.8.2013,  20:30 Найти цитируемый пост)
Неочевидно.

Ну, благодаря тому, что в числе 10 есть множитель двойка (а про двоичное машинное представление я уже говорил), предел, конечно, наступит. Каждое очередное умножение на двойку обнуляет очередной бит в хвосте мантиссы. Поскольку таких битов 63, то получаем максимальную итерацию - 63. Но если бы Вы захотели распечатать число, скажем, в 5-ричном виде, то конца бы не дождались)))

Цитата(akizelokro @  20.8.2013,  21:26 Найти цитируемый пост)
И не надо ничего делить на десять.

На 10 происходит неявное деление, как только Вы пишите:
Код
  long double x =0.456;

И вот тут машинное двоичное 0.456 не совпадает с нашим десятиричным 0.456 - чуть чуть, но отличается.

PS Сравнение чисел с плавающей точкой с нулём, вообще говоря, не корректно.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
akizelokro
Дата 21.8.2013, 07:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата

Есть! Только я не понимаю, как умножая на 10 Вы собираетесь свести ldval к нулю:


комментарии  пишутся для того, чтобы их читали

Код

              // взять целочисленную часть, образовавшуюся после умножения цифру и выдрать её в string


и почти это как раз вы сделали. (почему вы это сделали "почти", обяснение чуть ниже.
не надо было изначально умножать в цикле на 10 до упора, не обнуляя целую часть, и всё это пытаться поместить в int'овскую переменную.

и, кстати, из приведенного кода неочевидно, что 

Цитата

И вот тут машинное двоичное 0.456 не совпадает с нашим десятиричным 0.456 - чуть чуть, но отличается.


из-за куска в коде
Код

    x -= (int) x;

здесь опять же идёт интересный момент double -= (double)(int)double
поставьте число на вывод сразу после определения 
Код

long double x = .45600001;
, тогда это как аргумент и прокатит. а в реализации алгоритма просто надо выдерживать все тонкости.


Цитата(feodorv @  21.8.2013,  03:21 Найти цитируемый пост)
Но если бы Вы захотели распечатать число, скажем, в 5-ричном виде, то конца бы не дождались)))

конечно бы не дождался. такого варианта задачи я себе даже не ставил.

точный же метод решения задачи был мной сразу приведён.
сразу "хавать" введённое число с клавиатуры в string и парсить его.

Добавлено @ 07:23
в принципе, можно при реализации алгоритм и подправить, учесть знак, умножить на "-1" например,
если вообще интересует тогда уж строгое соответствие делает не сравнение, что не равно 0, а сравнение больше-равно нулю,
отнимать не (int)х, а  double-единицу в цикле пока число не станет меньше 1, чтобы не путаться лишний раз с приведением double к int и обратно.

Мораль сего спича такова, вообщем.
Если есть задача вывести целую или вещественную часть double-числа в строковый вид, то не надо налегать на int'ы. Это уже лишняя сущность и использовать её нужно желательно по минимуму, потому что в логике задачи не требуется.

Это сообщение отредактировал(а) akizelokro - 21.8.2013, 07:26


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
feodorv
Дата 21.8.2013, 08:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
Пользователь вводит число типа long double.
Оно должно быть прочитано как long double.
Необходимо вывести его в виде строки.

Моё (сугубо индивидуалистическое) видение решения задачи выглядит так:
Код
#include <iostream>

using namespace std;

int main( void )
{
  int digits = 20;             // Число значащих цифр, которые мы вычисляем; остальное забиваем нулями
  int power = 0;
  bool hasSign = false;

  long double ld;
  cin >> ld;
  if( ld < 0 )
  {
    ld = -ld;
    hasSign = true;
  }

  while( ld >= 1.0 )
  {
    ld /= 10;
    power++;
  }
  if( power == 0 && ld > 0 )
    while( ld < 0.1 )
    {
      ld *= 10;
      power--;
    }

  if( hasSign ) cout << '-';
  if( power <= 0 ) cout << "0.";
  while( power < 0 )
  {
    cout << '0';
    power++;
  }

  for( ;; )
  {
    if( digits > 0 )
    {
      ld *= 10;
      char d = (int) ld + '0';
      cout << d;
      ld -= (int) ld;
      if( power <= 0 && ld == 0 ) break;
    }
    else
      cout << '0';

    if( digits <= 0 && power <= 0 ) break;
    if( power == 1 ) cout << '.';
    power--;
    digits--;
  }

  cout << endl;
  return 0;
}


Результаты получаются такого рода:
Цитата

0
0.0

100
100.0

1e100
10000000000000006661000000000000000000000000000000000000000000000000000000000000000000000000000000000.0

0.01
0.01

0.0000000001
0.000000000100000000000000066610

1e-100
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000066610


Что не хорошо (помимо артефактов деления на 10).
Цитата

1e-307
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000999999999999999289450

1e-308
10547170639271385983000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0

1e308
100000000000000066610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0

1e1000
10547170639271385983000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0

Что-то мне подсказывает, что >> не умеет читать long double, а только double... Да и вообще, long double лишь синоним double (это у Microsoft).


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 21.8.2013, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(akizelokro @  21.8.2013,  08:09 Найти цитируемый пост)
комментарии  пишутся для того, чтобы их читали

Прошу прощения, пропустил, увлёкся кодом)))

Остальное ничего не понял(((

Цитата(akizelokro @  21.8.2013,  08:09 Найти цитируемый пост)
из-за куска в коде

1: x -= (int) x;

здесь опять же идёт интересный момент double -= (double)(int)double
поставьте число на вывод сразу после определения 

1: long double x = .45600001;

, тогда это как аргумент и прокатит. а в реализации алгоритма просто надо выдерживать все тонкости.

Если не нравится (double)(int)double (чем именно?) пользуйтесь modf. Что плохого в (double)(int)double? Ну и что, что лишнее приведение, главное, в точности потерь нет.
Какие тонкости нужно выдерживать? Как именно их выдерживать - вычитать по 1.0???


Цитата(akizelokro @  21.8.2013,  08:09 Найти цитируемый пост)
поставьте число на вывод сразу после определения 

И что это даст? Вы в курсе, что при этом будет задействован алгоритм, описанный ещё у Кнута, по "сглаживанию" вывода. То есть вывод != машинному представлению числа.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
akizelokro
Дата 21.8.2013, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата(feodorv @  21.8.2013,  08:39 Найти цитируемый пост)
Если не нравится (double)(int)double (чем именно?) пользуйтесь modf. Что плохого в (double)(int)double? Ну и что, что лишнее приведение, главное, в точности потерь нет.
Какие тонкости нужно выдерживать? Как именно их выдерживать - вычитать по 1.0???


Я просто не уверен, что в случае (double)(int)3.123 получится именно 3.0, а не опять очередная потеря точности Поэтому и не хочу применять преобразования double к int и обратно. Это к утверждению, почему возможно, что не аргумент в данном случае.

Цитата(feodorv @  21.8.2013,  08:39 Найти цитируемый пост)
И что это даст? Вы в курсе, что при этом будет задействован алгоритм, описанный ещё у Кнута, по "сглаживанию" вывода. То есть вывод != машинному представлению числа. 


Да ничего там не будет такого. А будет там просто считывание ввода сразу в строку - tcin >> <строка>.
Предположу, что как раз это и нужно автору темы (раз тема для новичков), а не подробные уже дебри.



--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
feodorv
Дата 21.8.2013, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(akizelokro @  21.8.2013,  11:32 Найти цитируемый пост)
Я просто не уверен, что в случае (double)(int)3.123 получится именно 3.0, а не опять очередная потеря точности

Может, я чего не понимаю, но невидно никаких подводных камней по этому поводу. Число x - хорошее, не inf, не nan, < 10 и >= 1, откуда потеря точности?


Цитата(akizelokro @  21.8.2013,  11:32 Найти цитируемый пост)
Да ничего там не будет такого. А будет там просто считывание ввода сразу в строку - tcin >> <строка>.
Предположу, что как раз это и нужно автору темы (раз тема для новичков), а не подробные уже дебри.

 smile Опять потерял нить разговора, ну да ладно  smile 

Код

int main( void )
{
  char buf[128];

  cin >> buf;
  cout << buf;

  return 0;
}


Это сообщение отредактировал(а) feodorv - 21.8.2013, 11:08


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
akizelokro
Дата 24.8.2013, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Давай говорить просто, про проверку изначальну. что число long double не   NAN или не infifnity, вспомнил только я.
про то, что не надо скопом всё сразу на червонец умножать, пока число не приведёт к переполнению, а отхватывать  после каждого умножения на 10, опять же вспомнил только я. (я в своём алгоритме даже не рассматриваю пределы максимальных значений int).
кроме простого вывода в строку (опят же написал я), есть ещё и варианты printf свыводом не на устройство вывода, а опять же в строку.
Если Кнут сделал алгоритм, то зашибись ( хотя какие мне дела до Кнута, я алгоритмист не хуже)


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

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


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1250 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.