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

Поиск:

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


Новичок



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

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



Добрый День!
Прошу помочь в написании кода преобразовании вещественной части long double в целочисленное значение.

То есть должно быть что-то типа:
long double ld = 123.456;
int c = func( ld); // c = 456

Проблема в том, чтобы написать эту процедуру func.
Число типа long double пользователь должен ввести с клавиатуры.
Точность заранее неизвестна.

Пробывал написать след. образом:
Код

#include <iostream>
using std :: cin;

int main( void)
{
     // Ввод вещественного значения типа long double
     long double ld;
     cin >> ld;

     // Целая часть
     int const ival = static_cast<int> (ld);

     // Вещественная часть
     long double ldval = ld - ival;

     // Преобразование вещественной части в целое
     while ( ldval != static_cast<int> (ldval) )
              ldval *= 10;

     return 0;
} /* main */


Задумка моя в том, чтобы каждый раз умножать на 10 до тех пор,
пока плавающая часть не станет равной 0.

То есть, если пользователь ввел: ld = 12.34, то ldval = 0.34
Далее в цикле ldval = 0.34, 3.4, 34.00

Но проблема в том, что 34.00 и 34 - это не два одинаковых числа, то есть разница
между ними не равна 0.  

Я прочитал про вещественные и целочисленные типы, понимаю, почему они не равны, но 
не представляю, как решить данную задачу.

Просьба помочь в решении данной задачи.
Может быть есть какая-то константа, позволяющая сравнивать на равенство целочисленные и вещественные типы?
Прежде чем задать вопрос я погуглить, но ничего полезного не нашел..
PM MAIL   Вверх
SenkraD
Дата 20.8.2013, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Ну вы же читали про вещественные типы smile, а там настоятельно рекомендуют сравнивать с заданой точностью тоесть как-то так:
Код

long long_value = 34;
long double double_value= 34.00;
if ((double_value - long_value) <= 0.001)
{
    std::cout << "values are equal" << std::endl;
}



--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
den140387
  Дата 20.8.2013, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(SenkraD @ 20.8.2013,  11:10)
Ну вы же читали про вещественные типы smile, а там настоятельно рекомендуют сравнивать с заданой точностью тоесть как-то так:
Код

long long_value = 34;
long double double_value= 34.00;
if ((double_value - long_value) <= 0.001)
{
    std::cout << "values are equal" << std::endl;
}

Спасибо! smile 
Я читал про них в Лафоре и Липпмане. 
Там говорится только то, что long double имеет точность в 19 цифр, если я правильно помню.
В связи с этим вопрос: почему вы выбрали именно "0.001", а не "0.01" или же "0.00001"?
Раз точность 19 цифр, то по идее 18-ть нулей должно быть, если я ничего не путаю..


PM MAIL   Вверх
feodorv
Дата 20.8.2013, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
Я прочитал про вещественные и целочисленные типы, понимаю, почему они не равны

Так, для понимания Вашего понимания, почему?


Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
преобразовании вещественной части long double

А что такое "вещественная часть long double"? Дробная часть? Тогда в общем случае задача не имеет (правильного) решения.


Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
То есть должно быть что-то типа:
long double ld = 123.456;
int c = func( ld); // c = 456


Ну, код, который Вы привели, несколько отличается от этого:

Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
     // Ввод вещественного значения типа long double
     long double ld;
     cin >> ld;


Отличие именно в том, что значение для long double не задано, а вводится с клавиатуры. Тогда задача имеет решение, ибо можно вводить его не сразу в long double, а в строку.
Затем эту строку можно проанализировать на тему, что это действительно строковое представление вещественного числа. А уже потом найти точку и вычислить искомое (с проверкой на переполнение).





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


Новичок



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

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



Цитата(feodorv @ 20.8.2013,  11:18)
Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
Я прочитал про вещественные и целочисленные типы, понимаю, почему они не равны

Так, для понимания Вашего понимания, почему?


Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
преобразовании вещественной части long double

А что такое "вещественная часть long double"? Дробная часть? Тогда в общем случае задача не имеет (правильного) решения.


Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
То есть должно быть что-то типа:
long double ld = 123.456;
int c = func( ld); // c = 456


Ну, код, который Вы привели, несколько отличается от этого:

Цитата(den140387 @  20.8.2013,  12:01 Найти цитируемый пост)
     // Ввод вещественного значения типа long double
     long double ld;
     cin >> ld;


Отличие именно в том, что значение для long double не задано, а вводится с клавиатуры. Тогда задача имеет решение, ибо можно вводить его не сразу в long double, а в строку.
Затем эту строку можно проанализировать на тему, что это действительно строковое представление вещественного числа. А уже потом найти точку и вычислить искомое (с проверкой на переполнение).

Цитата

Так, для понимания Вашего понимания, почему?

Как я понимаю, они просто по-другому в памяти машины представляются.
Для плавающих есть мантисса и экспонента, а для целочисленных - нет

Цитата

А что такое "вещественная часть long double"? Дробная часть? Тогда в общем случае задача не имеет (правильного) решения.

Ну как я понимаю, дробная часть с точностью до 19ти цифр.
А почему не имеет решения? Мне же известна максимальная точность long double: 19 цифр после запятой.

Цитата

Отличие именно в том, что значение для long double не задано, а вводится с клавиатуры. Тогда задача имеет решение, ибо можно вводить его не сразу в long double, а в строку.
Затем эту строку можно проанализировать на тему, что это действительно строковое представление вещественного числа. А уже потом найти точку и вычислить искомое (с проверкой на переполнение).

По поводу строки я уже сделал.
Было две задачи: 
1) Пользователь вводит строку.
Необходимо вывести это же значение в формате long double
Это я сделал.

2) Пользователь вводит число типа long double.
Оно должно быть прочитано как long double.
Необходимо вывести его в виде строки.
Целую часть в строку я преобразовал.
А вот с дробной возникла проблема.



PM MAIL   Вверх
SenkraD
Дата 20.8.2013, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Цитата(den140387 @  20.8.2013,  11:17 Найти цитируемый пост)
В связи с этим вопрос: почему вы выбрали именно "0.001", а не "0.01" или же "0.00001"?
тут уже от задачи зависит, а вам наверное подойдет std::numeric_limits<long double>::epsilon(). вот пример с msdn
Код
#include <iostream>
#include <limits>

using namespace std;

int main( )
{
    cout << "The difference between 1 and the smallest value greater than 1\n for float objects is: " 
            << numeric_limits<float>::epsilon( ) 
            << endl;
    cout << "The difference between 1 and the smallest value greater than 1\n for double objects is: " 
            << numeric_limits<double>::epsilon( ) 
            << endl;
    cout << "The difference between 1 and the smallest value greater than 1\n for long double objects is: " 
            << numeric_limits<long double>::epsilon( ) 
            << endl;
}

Код

The difference between 1 and the smallest value greater than 1 for float objects is: 1.19209e-007
The difference between 1 and the smallest value greater than 1 for double objects is: 2.22045e-016
The difference between 1 and the smallest value greater than 1 for long double objects is: 2.22045e-016



--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
feodorv
Дата 20.8.2013, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
Необходимо вывести его в виде строки.

Простите, но это совсем другая задача. Не нужно её сводить к нахождению дробной части в виде беззнакового целого.
Да и целая часть long double не обязана умещаться в int или long long. Что Вы будете делать с числом 10^100?


Задача (адекватного!) вывода значения double или long double не так проста. Но если требуется простое решение, то, действительно, можно ограничиться определённым количеством знаков (после запятой). Но при этом совсем не нужно представлять целую и дробную части в виде int.


Как бы Вы решили задачу строкового представления int? Вот аналогично решается и задача, стоящая перед Вами.

Добавлено через 9 минут и 13 секунд
Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
А почему не имеет решения? Мне же известна максимальная точность long double: 19 цифр после запятой.

В какую целочисленную переменную типа int Вы собрались запихивать 19 знаков?

Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
Как я понимаю, они просто по-другому в памяти машины представляются.

Проблема не в этом, а в том, что числа с плавающей точкой имеют двоичное машинное представление. То есть деление на два не разрушает мантиссу, а вот деление на 10 уже даёт приблизительный результат (то есть x / 10 * 10 может уже не равняться x). А мы хотим иметь именно 10тичное строковое представление, которое, увы, не обязано совпадать с нашими ожиданиями (вместо .34 может получиться .33999989889...)


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


Крокодил
**


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

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



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

Код

tstring tstr;
tcin >> tstr;
// здесь добавить проверку на то, что вообще введено число, а не эники-бэники
int pos = tstr.find(_T("."));
if(pos != -1)
{
      tstr = tstr.substr(pos + 1, tstr.length());
      size_type sz = 0;
      long long result = strtoll(tstr, &sz, 0);
}
else
     tcout << _T("Алгоритмисты, блин!");


Это в предположении, что ввод в десятичной системе, но без "E-2", например.



Это сообщение отредактировал(а) akizelokro - 20.8.2013, 14:16


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


Крокодил
**


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

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



Цитата

Было две задачи: 
1) Пользователь вводит строку.
Необходимо вывести это же значение в формате long double
Это я сделал.

2) Пользователь вводит число типа long double.
Оно должно быть прочитано как long double.
Необходимо вывести его в виде строки.
Целую часть в строку я преобразовал.
А вот с дробной возникла проблема.


Вообще-то, он в любом случае вводит строку, если считать для упрощения.
Есть в стандарте функции to_tstring (на самом деле to_string и to_wstring, но мне сподручней писать сразу to_tstring)
И разные функции обратного преобразования из строки в числовые значения stol, stoi, stod ..

Кажисть, правда в С++11 стандарте. но эти функции уже и студия даже поддерживает

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


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


Крокодил
**


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

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



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


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


Эксперт
****


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

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



Цитата(akizelokro @  20.8.2013,  15:43 Найти цитируемый пост)
Её пишете и целую часть отбрасываете, и снова повтор умножения на 10.

Всё так. Но:
Цитата(akizelokro @  20.8.2013,  15:43 Найти цитируемый пост)
 И там до тех пор пока результат не станет равен нулю.

Результат может никогда не стать равным нулю...



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


Новичок



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

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



Цитата

тут уже от задачи зависит, а вам наверное подойдет std::numeric_limits<long double>::epsilon(). вот пример с msdn

Спасибо! smile

Добавлено через 5 минут и 5 секунд
Цитата(feodorv @ 20.8.2013,  12:13)
Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
Необходимо вывести его в виде строки.

Простите, но это совсем другая задача. Не нужно её сводить к нахождению дробной части в виде беззнакового целого.
Да и целая часть long double не обязана умещаться в int или long long. Что Вы будете делать с числом 10^100?


Задача (адекватного!) вывода значения double или long double не так проста. Но если требуется простое решение, то, действительно, можно ограничиться определённым количеством знаков (после запятой). Но при этом совсем не нужно представлять целую и дробную части в виде int.


Как бы Вы решили задачу строкового представления int? Вот аналогично решается и задача, стоящая перед Вами.

Добавлено @ 12:23
Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
А почему не имеет решения? Мне же известна максимальная точность long double: 19 цифр после запятой.

В какую целочисленную переменную типа int Вы собрались запихивать 19 знаков?

Цитата(den140387 @  20.8.2013,  12:35 Найти цитируемый пост)
Как я понимаю, они просто по-другому в памяти машины представляются.

Проблема не в этом, а в том, что числа с плавающей точкой имеют двоичное машинное представление. То есть деление на два не разрушает мантиссу, а вот деление на 10 уже даёт приблизительный результат (то есть x / 10 * 10 может уже не равняться x). А мы хотим иметь именно 10тичное строковое представление, которое, увы, не обязано совпадать с нашими ожиданиями (вместо .34 может получиться .33999989889...)

Цитата

Как бы Вы решили задачу строкового представления int? Вот аналогично решается и задача, стоящая перед Вами.

c int - все просто. Я могу легко пройтись по всему целому числу и каждую цифру преобразовать в символ, путем
сложения с '0'. В случае обхода целочисленного значения, я могу легко получить условие того, что обработал
все цифры этого значения. А вот с вещественными типами проблема из-за того, что я не знаю, когда заканчивается
это число.

Добавлено через 7 минут и 26 секунд
Цитата

Результат может никогда не стать равным нулю..

+1.
В способе, который я привел в самом начале, происходило зацикливание.

PM MAIL   Вверх
akizelokro
Дата 20.8.2013, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


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

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



Цитата(feodorv @  20.8.2013,  17:43 Найти цитируемый пост)
Результат может никогда не стать равным нулю...


Неочевидно. Десять в минус какой степени там предел? tstring схавает. А если уж кому-то интересно, то можно break на пятитысячной итерации поставить.





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


Новичок



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

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



Цитата

Проблема не в этом, а в том, что числа с плавающей точкой имеют двоичное машинное представление. То есть деление на два не разрушает мантиссу, а вот деление на 10 уже даёт приблизительный результат (то есть x / 10 * 10 может уже не равняться x). А мы хотим иметь именно 10тичное строковое представление, которое, увы, не обязано совпадать с нашими ожиданиями (вместо .34 может получиться .33999989889...) 

Спасибо!  smile 
Вы гораздо более понятно объяснили, чем в книжке.
PM MAIL   Вверх
akizelokro
Дата 20.8.2013, 20:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


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

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



Цитата(den140387 @  20.8.2013,  19:21 Найти цитируемый пост)
В способе, который я привел в самом начале, происходило зацикливание.


Это где вы делали сравнение double с интом?
Ну-ну! Там вообще с вашим умножением на 10 в цикле может быть неизвестно что. Об этом вам писали уже. 
Вам надо было сравнивать именно с нулём (значение double), постоянно отсекая целую часть (появившуюся цифру), перенося её в строку. 
и там уже не нужны никакие ограничения на размер инта. Работа ведётся только с double и string.

А привлекать ещё дополнительный тип, когда можно обойтись и без него, нерационально.
Единственное, что его можно использовать для того, чтобы цифру, появлюящуюся после умножения на 10 вещественной части преобразовывать в литерал (строку).
Есть разница между 

Код

while ( ldval != static_cast<int> (ldval) )
              ldval *= 10;


и
Код

while ( ldval != 0 )
{
              ldval *= 10;
              // взять целочисленную часть, образовавшуюся после умножения цифру и выдрать её в string
}


А вот это именно и есть разница в подходах. Бритва Оккама. 
О чем и был мой первый пример кода. string может захавать сколько угодно цифр после запятой.


А проверку на NaN'ы и прочие эники-беники тоже реализуете

Добавлено через 29 секунд
И не надо ничего делить на десять.

Добавлено через 9 минут и 39 секунд
Просто double c int сравнивать никогда не надо. Так, совет на будущее. Потому что результат вообще неочевиден


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
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   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

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

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

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

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


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

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


 




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


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

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