![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
||||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
Если я буду иметь возможность хранить числа в дробях, где числитель и знаменатель могут быть представлены числами из 300 (что соответсвует максимальной емкости типа double) или дальше больше знаков, неужели этого не хватит для практических вычислений? Конечно, в определенный момент может наступить переполнение, но ведь оно может наступить и при работе с double. При этом работая с double точность теряется, чем больше вычислений мы производим, а при работе с дробями не теряется вообще.
|
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 12 Всего: 459 |
Какие еще 300 ? У дабла 15-16 цифр. Если нужно максимальное число цифр, то тут я думаю поможет __int64 . У него 19 значащих цифр. По размеру он как double, только не хранит в себе показатель степени и вообще сам по себе число целое. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
Я не про точность, а про емкость. Тип double может иметь максимальное значение состоящее из порядка трехсот знаков. При этом точность будет, как вы говорите, в 15-16-ти. А что если int будет иметь возможность хранить такие же большие числа? Он все равно не будет годиться для дробного представления чисел? Я тут набросал класс super_int, который может хранить числа примерно такой же размерности как и double. Вот если ими представить дробь, неужели в практических вычислениях все равно будет переполняться этот тип?
Основная идея - в каждом элементе массива value хранятся данные по трем разрядам. То есть число 123456 будет представлено как value[0] = 456, value[1] = 123, rang = 2. Таким образом можно хранить числа примерно 1E+300. Из математических операторов реализовал только оператор сложения super_int. Каковы перспективы представления дробей такими типами данных? То есть в числителе и знаменателе будут super_int. |
|||
|
||||
FCM |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 461 Регистрация: 30.3.2009 Репутация: нет Всего: 9 |
||||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 8 Всего: 72 |
Зачем было предложено хранить числа в виде дробей? чтобы избежать ошибок округления. Как только будет не хватать значащих цифр - будут ошибки округления, и цель не будет достигнута.
Кроме того, дроби помогут только при арифметических действиях, а ты упоминал про синус ... Вот как должно делаться некоторые операции с неограниченной разрядностью:
|
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
Так в том-то и штука, что если есть возможность представить числитель и знаменатель неограниченным количеством знаков (над реализацией надо подумать), то цель будет достигнута. Ведь все операции выполняются с целочисленными типами. По поводу тригонометрии и прочих математических операций - надо подумать. Главное здесь - это принципиальная возможность достижения условно неограниченной точности вычислений с использованием чисел, представленных в виде дроби с условно бесконечным числителем и знаменателем. Ну например - неужели не хватит для практических вычислений использование дробей, где числитель и знаменатель могут состоять из миллиона значащих цифр? |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 8 Всего: 72 |
Ну попробуй, используя только обычный int, без потери точности посчитать сумму первых членов ряда в виде дроби: 1 + 1/2 + 1/3 + 1/5 + 1/7 + 1/11 + 1/13 + ... + 1/p До какого p хватит точности? Сложение с неограниченным числом знаком, умножение и деление на обычное число, преобразование к десятичному виду я тебе написал (для чисел без знаков). Возможно, в коде есть ошибки - писал прямо на экране. Например, нет оператора копирования. Вычитание делается аналогично сложению. Умножение в столбик написать тоже очень просто, быстрое умножение - сложнее. Нужно добавить код для убирания незначащих нулей. Преобразовывать в десятичный вид и обратно можно сразу по 9 цифр - деля и умножая на 1000000000U. Дробь можно хранить в виде структуры (знак, числитель, знаменатель); |
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
А зачем использовать обычный int? Надо использовать super_int с неограниченным количеством значащих цифр (ну, конечно, условно неограниченным). С вашим классом я, к сожалению, не разберусь. Либо у меня знаний языка не хватает, либо у вас опечатки. Наример член класса data указывает на неизвестный мне тип unsigned. |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 8 Всего: 72 |
unsigned - это ключевое слово языка C++. эквивалентно unsigned int - тот же int, но без знака.
Если вам нужно для дробей, знак проще учитывать отдельно, чем реализовавать знаковую арифметику. data указывает на массив беззнаковых unsigned int длиной length. В полной реализации нужно две length: сколько выделено и сколько используется. data[0] - младшие 32 бита, data[1] - следующие 32 бита и т.д. Реализуется сложенене, вычитание, умножение, деление "в столбик", c "цифрой" unsigned int (беззнакое 32-разрядное целое в диапазоне 0..0xFFFFFFFFu). При операциях с такими "цифрами" используется typedef unsigned __int64 uint64 - беззнакое 64-разрядное целое в диапазоне 0..0xFFFFFFFFFFFFFFFFuLL - две 32-разрядные "цифры" - чтобы не было переполнение. старшая "цифра" получается сдвигом на 32 бита. |
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
Вот ваш оператор сложения. Прокомментируйте вопросы, которые я закомментировал.
|
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 8 Всего: 72 |
|
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
math64, попробовал реализовать ваш класс. Исправил опечатки и мелкие неточности. Не разобрался с вашей функцией toString, мне проще применить для индекации возвращаемое значение типа UnicodeString. Но и без этой функции возникли ошибки утечки памяти. Что-то надо дорабатывать. И еще я так понял надо в класс добавить переменную, хранящую знак числа.
И вообще, насколько я понимаю суть вашего класса в том, что это "супер число" равно сумме чисел массива data? Это ж сколько может понадобиться памяти, чтобы представить число с миллионом значащих цифр?... Мне кажется это не лучший вариант. Я тут переделал свой класс super_int. Число хранится в std::vector<short int> value. Каждый элемент вектора не более 9999. Например число 111122223333 будет записано в таком векторе так value[0] = 3333, value[1] = 2222, value[2] = 1111. Мне кажется перспектив у такой конструкции больше с точки зрения хранения больших чисел с меньшими затратами памяти. На малых числах этот тип скорее будет проигрывать. Ведь если таким образом хранить число 1 уходит 32 байта. Правда я не урезаю вектор под фактическую заполненность. Он ведь вроде резервирует пустые ячейки для записи. Это сообщение отредактировал(а) Нитонисе - 31.8.2012, 17:01 |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 8 Всего: 72 |
std::vector<> хранит внутри себя массив + небольшую кучку информации - простой массив, однозначно, требует меньше места.
Ты хранишь в каждом short число от 0 до 9999, когда unsigned short может хранить числа от 0 до 65535 - у тебя однозначно, уйдёт больше памяти. У меня числа хранятся в двоичном виде - компактнее не придумаешь (с условием без потери точности). Но сложнее преобразовывать в десятичную систему. Я использую unsigned (32 разряда) и unsigned __int64 (64 разряда) вместо unsigned short (16 разрядов) и unsigned - это не даёт экономии памяти, но ускоряет вычисления. (32 разряда - не менее 9 десятичных цифр, против твоих 8 цифр в двух short) Утечка памяти - я упоминал, что нужен оператор присваивания. без него будет утечка. По уму, нужно реализовывать так:
Проверил - код работает. Учти: я пишу объявление методов класса и реализацию вместе для краткости; тебе их нужно будет разнести на .h и .cpp Если пользуешься Visual Studio - можешь рассмотреть возможность перехода на C#. Там есть BigInteger готовом виде. BigInteger есть также а Java - с исходниками (алгоритмы можно стянуть оттуда). Наверняка есть готовая реализация и на C++ - но придётся искать в инете. Это сообщение отредактировал(а) math64 - 1.9.2012, 20:30 |
|||
|
||||
Нитонисе |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 917 Регистрация: 5.11.2009 Репутация: нет Всего: 2 |
Я пишу в C++ Builder XE и разделять код на заголовочный файл и файл реализации необязательно, скинул все в файл h и отредактировал (у вас было много опечаток). Проект скомпилирвал, но при попытке сложить два простых числа выдал ошибку, подсветив строку деструктора, где освобождается память в data. Я не стал дальше разбираться. Конечно ваш метод привлекает тем, что память используется максимально компактно и арифметические действия вроде просто реализуются (у меня сложнее). Возможно и скорость вычислений будет выше (хотелось бы кстати сравнить). Но мне с вашим кодом сложно разобраться ![]() По поводу памяти выделяемой для моего типа данных. Использую std::vector<short int>. Выделяемая память - sizeof(super_int) = 32 байта. Добавил переменную short int для хранения знака. Размер почему-то стал 40 байт, хотя по идее должен был стать 34. Судя по размеру вектора - при инициализации он зарезервировал 32/2=16 ячеек. А это значит, что максимальное число, котороя я могу в него помсетить без дополнительного выделения памяти - 9999 E+60. Какое максимальное число вы можете разместить в своем SuperInt в таком же объеме памяти (32 байта)? Это сообщение отредактировал(а) Нитонисе - 31.8.2012, 21:50 |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |