Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: округление  (Прочитано 22331 раз)
0 Пользователей и 7 Гостей смотрят эту тему.
Mfcer__
Команда клуба

ru
Offline Offline

« : 20-12-2004 16:39 » 

Есть число типа double допустим равное 12378134664681 (здесь может быть любое число)
Задача состоит в том чтобы превратить это число в 0.12378134664681
То есть просто представить число как часть после запятой

Как можно реализовать?
Метод должен быть по возможности быстрым, хотя подойдут любые варианты
Записан
Olegator
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 20-12-2004 19:03 » 

С помощью цикла с постусловием делишь на 10.0 до тех пор пока число не станет < 1.

double n;
 do
   n=n/10.0;
 while (n>=1);
printf("%lf",n)
Записан
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #2 : 20-12-2004 20:53 » 

а если число типа double и равно 18644868E67 то придется сделать больше 67 делений для одного преобразования что не очень оптимально  :?
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 20-12-2004 22:06 » 

Вот может такая идейка подойдет, код конечно можно оптимизировать, это на скорую руку, также можно менять коэффициент но которе происходит сдвиг (самое главное-это смысл Улыбаюсь )
Код:
#include <stdio.h>
#include <conio.h>
void main ()
{
clrscr();
double point;
double koef=10,s=1;
printf("input point");
scanf("%lf",&point);

do
{
s=1;
if(point<0.1)
{
for(int i=0; point<0.1;i++,s*=10)
{point*=koef*s;}
}
//////////////
s=1;
if(point>1)
{
for(int i=0; point>1;i++,s*=100)
{point/=koef*s;}
}
}
while(!(point<1&&point>0.1));
cout<<"\n"<<point;
return;
}

Выводит число не целиком, но на самом деле, там то что надо, в инспекторе можешь посмотреть.
« Последнее редактирование: 03-12-2007 17:24 от Алексей1153++ » Записан

ещё один вопрос ...
Alf
Гость
« Ответ #4 : 20-12-2004 22:33 » 

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

В данном примере:

1. Берем исходное число - 123781344664681
2. Вычисляем его логарифм по основанию 10:
Log10(123781344664681) = 14.09265519622138561074672569222
(разумеется, такая точность здесь излишня, я просто копирую результат из штатного калькулятора Windows).
3. Берем целую часть логарифма (14) и прибавляем 1, получаем 15.
4. Делим исходное число на 10 в степени 15, получаем:
123781344664681/(10^15) = 0.123781344664681

В общем случае, если исходное число X, искомое число Y определяется формулой:

Y = X / (10 ^ (INT(LOG10(X)) + 1)),
где
^ - операция возведения в степень,
INT - функция взятия целой части числа,
LOG10 - логарифм числа по основанию 10.

Поскольку компы без математического сопроцессора уже канули в Лету, думаю, такая конструкция будет работать поэффективнее деления в цикле при достаточно большом значении X.
Записан
LEON
Гость
« Ответ #5 : 21-12-2004 10:42 » 

А если число перевести в строку, слева дописать 0. и обратно в double?
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 21-12-2004 14:25 » 

Из double в string(Delphi) или в char (С) перевести нельзя.
Записан

ещё один вопрос ...
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 21-12-2004 14:26 » 

Из double в string(Delphi) или в char (С) перевести нельзя.
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #8 : 21-12-2004 14:56 » 

Из double в string(Delphi) или в char (С) перевести нельзя.
Посредством sprintf можно. Только очень сомнительно, что окажется эффективнее вычисления логарифма при большом количестве значащих цифр.
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 21-12-2004 15:32 » 

На сколько я помню, функция printf выводит числа ограниченной длины, там не больше 6 символов, если я не ошибаюсь.
Интересно, на sprintf такие ограничения распространяются
Записан

ещё один вопрос ...
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 21-12-2004 15:54 » 

на печать выводится любое количество знаков, это можно настроить в строке формата.

Непонятно другое -- что делать с этим дальше?  Ну получится строка "1,234567890123456e+78", и что?  надо разбирать строку, выделять мантиссу и показатель,  потом мантиссу переводить в число.  Но при этом число изменится -- либо часть знаков потеряется из-за недостаточной точности, либо новые получатся, если точность печати превышает точность мантиссы.  нехорошо и то, и другое.

Я думаю, что десятичный логарифм -- наиболее подходящее решение.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #11 : 21-12-2004 23:52 » 

   double a = 12812896757;
   int po = ((int)log10(a))   +1;
   cout << po  << endl;
   double val = pow(10,po);
   cout << val << endl;
   printf("%lf",a/val);
   a /= val;
   if ( a == 0.12812896757  ) // это условие не срабатывает, а на экран выводиться всякий бред... Жаль
   cout << "Asasfaf" << endl;
Записан
maa
Участник

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 22-12-2004 04:31 » 

У меня твой код великолепно отработал.
Компилятор - Visual C++ 6.0.
Добавил только инклюды и main () {...}

#include <math.h>
#include <iostream.h>
#include <stdio.h>

« Последнее редактирование: 22-12-2004 04:33 от maa » Записан
Alf
Гость
« Ответ #13 : 22-12-2004 07:50 » 

...
   if ( a == 0.12812896757 ) // это условие не срабатывает, а на экран выводиться всякий бред... Жаль
   cout << "Asasfaf" << endl;
Выбрось это условие и поставь вместо него безусловную печать значения a.

Ни в коем случае нельзя сравнивать величины типа double и float на равенство, а тем более с литеральной константой.
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 22-12-2004 08:31 » 

А идея просто забить эхпоненту нулями не подходит?
« Последнее редактирование: 22-12-2004 08:34 от PSD » Записан

Да да нет нет все остальное от лукавого.
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #15 : 22-12-2004 11:06 » 

А идея просто забить эхпоненту нулями не подходит?

Это как ?
Можно поподробнее...
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 22-12-2004 12:18 » 

Точно не скажу но из курса ПТЦА помню что числа сплавующей точкой хранятся в формате
+|Мантиса|+|экспанента
(в каком порядке  они лежат в double не знаю, поищи в MSDN)
Причем мантиса всегда хранится в нормализованом виде те  0.123456
если эти правила дествуют и для типа double  то для того чтобы из  12323456787 получить
0.12323456787 достаточно зделать экспаненту раной 1.Для формата double  это заменить 12 бит на константу. Только я не уверен что  число там нормализованное...
Записан

Да да нет нет все остальное от лукавого.
Pu
Большой босс

ru
Offline Offline
78


« Ответ #17 : 24-12-2004 08:24 » 

в каком порядке лежат написано и нарисовано очень понятно здесь -
http://www.sibsutis.ru/~mavr/MP/cod.htm
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
pilpilon
Гость
« Ответ #18 : 25-12-2004 15:32 » 

#include <iostream>
#include <iomanip>
#include <sstream>

 using namespace std;

string mant ( double);
double input_double();

int main()
{
 cout << "mant = " <<    mant(input_double()) << endl;
 return 0;
}

string mant ( double arg )
{
  ostringstream os;
  os <<"  " << fixed <<
        setprecision(24) <<   
        arg << endl;
  int pointpos = os.str().find('.');
  os.seekp(0);
  os << "0.";
  return os.str().erase(pointpos,1).substr(0,26);
}
   
double input_double()
{
   double arg = .0;
    cout << "enter double number" << endl;
    cin >> arg;
   return arg;
}
задаснка не столько про double , сколько про манипуляцию строками. А вот выгрызать мантиссу -- точно не будет работать нигде, кроме компьютера на котором скомпилировано Улыбаюсь ю
« Последнее редактирование: 20-12-2007 20:34 от Алексей1153++ » Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 27-12-2004 06:50 » 

Цитата
задаснка не столько про double , сколько про манипуляцию строками. А вот выгрызать мантиссу -- точно не будет работать нигде, кроме компьютера на котором скомпилировано Улыбаюсь ю

Обоснуй почему не будет работать? Я предпологал я то это должно работать как минимум на всем семействе 80х86!
Записан

Да да нет нет все остальное от лукавого.
pilpilon
Гость
« Ответ #20 : 27-12-2004 15:54 » 

Ты хочешь сказать, что длина <double> на машинах 80х86 никогда не менялась ? и не будет? и что формат <double> универсален для процессора, а не , например, операционной системы / компилятора ?  что мантисса всегда нормализована?

Кроме того, в общем случае это не сильно эффективно. Ну есть у тебя число 12345678912345678. ну выгрыз ты его мантиссу ...
 получил, допустим, битовое представление числа 12345678912345678 ( допустм оно все в мантиссу влезло) - эту радость все равно надо хотя бы в < long>  перевести, а еще потом делить...
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 28-12-2004 06:01 » 

Ты не прав в первом но прав во втором:
По логике вещей тип добл обязан быть доинаков в рамках всего семества 80х86 как и все другие типы данных иначе старые программы просто бы не работали...  первая констаната типа доубл похерела работу прораммы на камне использующем другой формат...

По второму вопросу ты прав я не учел что 9 и 0.9 имеют разню мантису....

 
Записан

Да да нет нет все остальное от лукавого.
baldr
Команда клуба

cy
Offline Offline
Пол: Мужской
Дорогие россияне


WWW
« Ответ #22 : 28-12-2004 08:10 » new

Я уже не понимаю про что тут спор. Ноги растут из перевода в строку а потом обратно? Это ж бред.
По-моему давным-давно Alf дал единственно верный и лучший вариант. За что ему плюс. Улыбаюсь
Записан

Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
pilpilon
Гость
« Ответ #23 : 28-12-2004 13:22 » 

Зависит от того, что надо сделать с результатом. Если вывести на печать, то надо один раз перевести в строчку и дальше работать с ней - будет всяко быстрей. Если же от результата нужно взять арксинус -- другое дело. (Но тогда не важно, как число записывается, важно, чему оно примерно равно). Тут <Alf> все правильно написал, ( хотя как быстро вычисляться будет
< val/pow(10.0 , ceil( log10( val ) ) ) >  я судить не берусь, если повезет , то очень быстро, если нет - может и медленней, чем со строчкой.

Я в основном  имел в виду , что в <C++> можно перевести <double> в <string>, причем так, как душе угодно, операция это эффективная и бояться ее не надо ( в тех случаях когда именно это и нужно)
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines