Диапазон целых чисел содержит по крайней мере один полный квадрат?

Учитывая два целых числа a и b, есть ли эффективный способ протестировать, существует ли другое целое число n таким образом, что a ≤ n2 < b?

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

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

Примеры:

  • intervalContainsSquare(2, 3) => ложь
  • intervalContainsSquare(5, 9) => ложь (примечание: 9 вне этого интервала),
  • intervalContainsSquare(9, 9) => ложь (этот интервал пуст),
  • intervalContainsSquare(4, 9) => верный (4 в этом интервале),
  • intervalContainsSquare(5, 16) => верный (9 в этом интервале),
  • intervalContainsSquare(1, 10) => верный (1, 4 и 9 вся внутренняя часть этот интервал),

27
задан Community 23 May 2017 в 12:23
поделиться

8 ответов

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

Точно так же для этой проблемы вы можете выполнить предварительное вычисление, чтобы определить, что sqrt (b) -sqrt (a)> = 1, что затем означает, что a и b находятся достаточно далеко друг от друга, и между ними должен быть квадрат. Для некоторой алгебры это неравенство эквивалентно условию, что (ba-1) ^ 2> = 4 * a, или, если вы хотите его в более симметричной форме, что (ab) ^ 2 + 1> = 2 * (a + б). Таким образом, это предварительное вычисление может быть выполнено без квадратных корней, только с одним целым произведением и некоторыми сложениями и вычитаниями.

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

Если эти предварительные вычисления неубедительны, то я не могу придумать ничего, кроме решения всех остальных, a <= ceil (sqrt (a)) ^ 2


Поскольку возник вопрос о правильном выполнении алгебры:

sqrt(b)-sqrt(a) >= 1
sqrt(b) >= 1+sqrt(a)
b >= 1+2*sqrt(a)+a
b-a-1 >= 2*sqrt(a)
(b-a-1)^2 >= 4*a

Также: Обычно, когда a - большое число, вы должны вычислить sqrt (a) с помощью метода Ньютона или с помощью таблицы поиска, за которой следует несколько шагов метода Ньютона .В принципе, вычислить ceil (sqrt (a)) быстрее, чем sqrt (a), потому что арифметика с плавающей запятой может быть упрощена до целочисленной арифметики, и поскольку вам не нужно столько шагов метода Ньютона для достижения высокой точности, которая ты просто собираешься выбросить. Но на практике функция числовой библиотеки может быть намного быстрее, если она использует квадратные корни, реализованные в микрокоде. Если по какой-либо причине у вас нет этого микрокода, который мог бы вам помочь, возможно, стоит вручную написать ceil (sqrt (a)). Возможно, наиболее интересным будет случай, если a и b - неограниченные целые числа (например, тысяча цифр). Но для целых чисел обычного размера на обычном не устаревшем компьютере вы не сможете превзойти FPU.

26
ответ дан 28 November 2019 в 05:01
поделиться
  1. получить квадратный корень из меньшего числа и округлить его
  2. получить квадратный корень из большего числа и округлить его в меньшую сторону
  3. , если 1 меньше или равно 2, будет быть точным квадратом
4
ответ дан 28 November 2019 в 05:01
поделиться

Если вы согласитесь вычислять два квадратных корня, из-за его монотонности у вас есть это неравенство, которое эквивалентно вашему исходному:

sqrt(a) <= n < sqrt(b)

таким образом, если floor (sqrt (a))! = Floor (sqrt ( b)) , floor (sqrt (b)) - 1 гарантированно будет таким n .

4
ответ дан 28 November 2019 в 05:01
поделиться

Найдите интеграл от sqrt(a) и sqrt(b), скажем sa и sb.

Если sa2 = a, то выведите yes.

Если sb2 = b и sa = sb-1, то выведите "нет".

Если sa < sb, то выведите "да".

Иначе выведите "нет".

Вы можете оптимизировать вышесказанное, чтобы избавиться от вычисления sqrt(b) (аналогично ответу JDunkerly).

Или вы хотите избежать вычисления квадратных корней из a и b?


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

Вы начинаете с угадывания n, n = 1 и вычисляете n2

Рассмотрим, что если a <= n < b, то можно остановиться.

Если n < a < b, вы удваиваете угаданное n. если a < b < n, то приближаете его к среднему значению текущей + предыдущей догадки.

Это займет O(logb) времени.

2
ответ дан 28 November 2019 в 05:01
поделиться

В дополнение к хорошему решению Дж. Дункерли (+1), может быть возможное улучшение, которое необходимо протестировать и которое использует целые квадратные корни для вычисления целых квадратных корней

]
0
ответ дан 28 November 2019 в 05:01
поделиться

Получите квадратный корень из меньшего числа. Если это целое число, то все готово. В противном случае округлите число и возведите в квадрат. Если это меньше, чем b, значит, это правда.

Таким способом вам нужно вычислить только один квадратный корень.

Чтобы избежать проблемы, когда a равно b, вы должны сначала проверить это. Поскольку этот случай всегда ложный.

18
ответ дан 28 November 2019 в 05:01
поделиться

Почему вы надеетесь полностью избежать использования квадратных корней? Еще до того, как вы подошли к наиболее эффективному способу решения этой проблемы, вы видели методы, требующие всего 2 квадратных корня. Это делается за O (1) раз, поэтому мне кажется, что любое улучшение, которое вы могли бы надеяться сделать, потребовало бы больше времени, чтобы подумать, чем оно КОГДА-ЛИБО сэкономило бы ваше вычислительное время. Я не прав?

0
ответ дан 28 November 2019 в 05:01
поделиться

Один из способов - использовать метод Ньютона для нахождения целочисленного квадратного корня для b . Затем вы можете проверить, попадает ли это число в диапазон. Я сомневаюсь, что это быстрее, чем простой вызов функции извлечения квадратного корня, но, безусловно, интереснее:

int main( int argc, char* argv[] )
{
    int a, b;
    double xk=0, xk1;
    int root;
    int iter=0;
    a = atoi( argv[1] );
    b = atoi( argv[2] );

    xk1 = b / 32 + 1;  // +1 to ensure > 0
    xk1 = b;
    while( fabs( xk1 - xk ) >= .5 ) {
        xk = xk1;
        xk1 = ( xk + b / xk ) / 2.;
        printf( "%d) xk = %f\n", ++iter, xk1 );
    }

    root = (int)xk1;

    // If b is a perfect square, then this finds that root, so it also
    // needs to check if (n-1)^2 falls in the range.
    // And this does a lot more multiplications than it needs
    if ( root*root >= a && root*root < b ||
         (root-1)*(root-1) >= a && (root-1)*(root-1) < b )
        printf( "Contains perfect square\n" );
    else
        printf( "Does not contain perfect square\n" );

    return 1;
}
0
ответ дан 28 November 2019 в 05:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: