//-----------------------------------------------------------------------------------
template<class C> longint temp_sqrt( const C &num )
{
// Вычисляем потолок для корня из num
int i = 0; // № cтепени двойки, превышающей искомый корень
longint x( static_cast<uint32>(1) ); // cтепень двойки, превышающая искомый корень
for( ; sqr( x ) < num; x <<= 1, i++ );
// Делением попалам отрезка между последовательными степенями двойки уточняем
// первое приближение сверху с точностью до 1
if( i > 1 )
{
longint subst = x >> 2; // вычитаемое
longint middle; // середина текущего отрезка
longint temp;
for( ; i != 1 ; i-- ) // до тех пор, пока расстояние (вычитаемое == 0) не будет равно 1
{
middle = x - subst;
temp = sqr( middle );
if( temp > num ) x = middle;
else
if( temp == num ) return middle;
subst >>= 1;
}
}
return x;
}
//-----------------------------------------------------------------------------------
fraction sqrt( const fraction &f )
{
// Вычисление квадратного корня
if( f < static_cast<uint32>(0) ) throw range_check_error("sqrt");
// Вдруг корень рациональный ?
const fraction temp( temp_sqrt( f.numerator()), temp_sqrt( f.denominator()) );
if( sqr( temp ) == f ) return temp;
// Если корень иррациональный уточняем первое приближение x_(n+1)-ое до потолка искомого корня
fraction x_n1( temp_sqrt( f ) );
fraction x_n ( 0 ); // x n-ое
while( abs( x_n1 - x_n ) >= eps ) // метод Ньютона для функции x**2 - f
{
x_n = x_n1;
x_n1 = ( x_n + f / x_n ) / static_cast<uint32>(2);
}
return x_n1;
}
математические функции при работе с длинными числами
Пусть у нас есть некоторый класс, скажем, longint, который реализует целочисленную арифметику любой точности в некоторой системе счисления ( пусть, например, будет степенью двойки :). Пусть у нас есть класс fraction вида { longint numerator, denominator; }; реализующий арифметику обыкновенных дробей.
Проблема: реализуя, например, функцию вычисления корня квадратного из 9 методом Ньютона получаю, если в десятичную систему перевести что-то вроде
271050543121376108501863200217485427856445313 /
90350181040458702833954400072495142618815104
при определенной оценке погрешности.
Вопрос: как хорошо можно округлять или что-нибудь делать чтоб три получать?
Может чем поможет ссылка:
А по другому нельзя организовать структуру для хранения длинных чисел? Возможно имеются решения при другой организации данных.
Цитата:
Вопрос: как хорошо можно округлять или что-нибудь делать чтоб три получать?
Наверное, нужно помыслить над соотношением [(делитель - остаток) / делитель] и прикрутить его к вашей оценке погрешности...
Я долгое время просто не обращался к ней. Сделано было так. С учетом того, что корень из рационального числа будет числом рациональным в том случае, если и числитель, и знаменатель числа исходного являются полными квадратами, мы делаем так:
Считаем "потолок" корня из числителя. Считаем "потолок" корня из заменателя. Весь этот счет ведем с учетом того, что некоторый временный результат может быть искомым корнем. Если число иррациональное, применяем метод Ньютона.
Код:
В качестве примера можно отметить, что корень из 2000, без применения предварительной подготовки и с оценкой погрешности 1/100000000000000000000, выдавал число, имеющее в числителе и в знаменателе порядка 150 разрядов в системе счисления 2**32, с подготовкой знаков стало 5.