Как найти квадраты чисел в диапазоне

You can simplify the arithmetic by using

(n + 1)**2 == n**2 + (2*n + 1)

Here’s how to do that using a generator function:

import math

def squares(lo, hi):
    root = int(math.ceil(lo ** 0.5))
    num = root ** 2
    delta = 2 * root + 1
    while num <= hi:
        yield num
        num += delta
        delta += 2

print list(squares(4, 16))
print list(squares(5, 50))
print list(squares(20, 90))

output

[4, 9, 16]
[9, 16, 25, 36, 49]
[25, 36, 49, 64, 81]

Here’s an equivalent iterator class. I’ve given it a __repr__ method so it looks nice if you print an instance of this class.

import math

class Squares(object):
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop
        root = int(math.ceil(start ** 0.5))
        self.num = root ** 2
        self.delta = 2 * root + 1

    def __repr__(self):
        return 'Squares(%d, %d)' % (self.start, self.stop)

    def __iter__(self): 
        return self

    def next(self):
        num = self.num
        if num > self.stop:
            raise StopIteration
        self.num += self.delta
        self.delta += 2
        return num

sq = Squares(4, 16)
print sq
for i in sq:
    print i

print list(Squares(5, 50))
print list(Squares(20, 90))

output

Squares(4, 16)
4
9
16
[9, 16, 25, 36, 49]
[25, 36, 49, 64, 81]

For Python 3, replace the next method name with __next__.

The usual Python range convention is to stop before you reach the high limit. To make this code comply with that convention, in the squares() generator change

while num <= hi:

to

while num < hi:

and in the Squares() class, change

if num > self.stop:

to

if num >= self.stop:

0 / 0 / 0

Регистрация: 15.04.2022

Сообщений: 1

1

15.04.2022, 10:57. Показов 6251. Ответов 20


Студворк — интернет-сервис помощи студентам

Необходимо найти все числа на отрезке от А до B (А и B вводим) , которые являются полными квадратами. Если в заданном диапазоне таких чисел нет вывести -1.

Пример вводных данных и ответа :

Ввод : 1 30
Ответ : 1 4 9 16 25

Ввод : 10 50
Ответ : 16 25 36 49



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

15.04.2022, 10:57

20

Пифагор

2169 / 1652 / 840

Регистрация: 10.01.2015

Сообщений: 5,184

15.04.2022, 11:57

2

Python
1
2
3
n, m = map( int, input('Введите 2 числа через пробел: ').split() )
res = [i for i in range(n, m+1) if i**0.5 == round(i**0.5)]
print(res if res else -1)



1



eaa

15.04.2022, 13:28

Не по теме:

Пифагор, медленно) можно быстрее же посчитать



0



Пифагор

2169 / 1652 / 840

Регистрация: 10.01.2015

Сообщений: 5,184

15.04.2022, 13:37

4

eaa, а почему “не по теме”? Полагаю, через циклы без range() и списка? Потому, что остануться только арифметические операции:

Python
1
2
3
4
while n <= m:
    if n**0.5 == round(n**0.5):
        print(n)
    n+=1



0



Gdez

Эксперт Python

7254 / 4043 / 1779

Регистрация: 27.03.2020

Сообщений: 6,869

15.04.2022, 13:49

5

Пифагор,

Python
1
res = [i*i for i in range(ceil(n**.5), int(m**.5)+1)]



0



2169 / 1652 / 840

Регистрация: 10.01.2015

Сообщений: 5,184

15.04.2022, 14:00

6

Gdez, это получается быстрее? Тут и модуль подключается, и приведение к типу, и создание списка, и сам range(). Возможно, возможно. Я не замерял время выполнения, но сдается мне, цикл и чистая арифметика(не считая round()) – самое быстрое решение.



0



Gdez

Эксперт Python

7254 / 4043 / 1779

Регистрация: 27.03.2020

Сообщений: 6,869

15.04.2022, 14:06

7

Пифагор,

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import time
t1 = time.time()
from math import ceil
n, m = 1000000,2000000 #map( int, input('Введите 2 числа через пробел: ').split() )
res = [i*i for i in range(ceil(n**.5), int(m**.5)+1)]
print(time.time()-t1)
 
##########################
 
t2 = time.time()
n, m = 1000000, 2000000 #map( int, input('Введите 2 числа через пробел: ').split() )
res = [i for i in range(n, m+1) if i**0.5 == round(i**0.5)]
print(time.time()-t2)



1



2169 / 1652 / 840

Регистрация: 10.01.2015

Сообщений: 5,184

15.04.2022, 14:26

8

Gdez, а за счет чего код так быстро исполняется?



0



Эксперт Python

7254 / 4043 / 1779

Регистрация: 27.03.2020

Сообщений: 6,869

15.04.2022, 14:32

9

Пифагор, допустим диапазон = [1, 100]. Он содержит 10 полных квадратов. У меня счетчик цикла == 10. У Вас == 100



1



2169 / 1652 / 840

Регистрация: 10.01.2015

Сообщений: 5,184

15.04.2022, 14:42

10

Gdez, цифры увидел, но не совсем понял, как они формируются. В данном случае, 10 циклов вместо 100 получается из-за отсутствия ветвления и сравнения?



0



Эксперт Python

7254 / 4043 / 1779

Регистрация: 27.03.2020

Сообщений: 6,869

15.04.2022, 15:38

11

Пифагор,
ceil(n**.5) ^ 2 -> ближайший полный квадрат, больший “n”
int(m**.5) ^ 2 -> ближайший полный квадрат, меньший “m”
Соответственно квадраты чисел из диапазона [ceil(n**.5), int(m**.5)] и будут решением задачи
Как то так…



1



Catstail

Модератор

Эксперт функциональных языков программированияЭксперт Python

35328 / 19429 / 4065

Регистрация: 12.02.2012

Сообщений: 32,458

Записей в блоге: 13

15.04.2022, 16:21

12

Не могу одобрить эти коды. Они используют плавающую точку, а значит для 16-и и более разрядных чисел начнут безбожно врать. Смотрите:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def isSquare_1(x):
    if x in (0,1,4):
        return True
    a=1
    b=x//2
    while abs(a-b)>1:
        #print(a,b)
        c=(a+b)//2
        if c*c==x:
            return True
        elif c*c>x:
            b=c
        else:
            a=c
    else:
        return False
 
def isSquare_2(n):
    return n**0.5 == round(n**0.5)
 
x=1267650600228229401496703205376  # большое число
xx=x*x                                                    # его квадрат
xy=x*x-1                                                 # его квадрат-1 
 
print("Правильный тест:")
print(isSquare_1(xx))           # True
print(isSquare_1(xy))           # False
print("Неправильный тест:")            
print(isSquare_2(xx))           # True
print(isSquare_2(xy))           # True  !!!



3



enx

15.04.2022, 17:11

Не по теме:

Catstail, как всегда, чистая алгоритмическая магия :drink:



0



eaa

Status 418

Эксперт Python

3840 / 2124 / 568

Регистрация: 26.11.2017

Сообщений: 4,986

Записей в блоге: 2

15.04.2022, 22:59

14

Python
1
from math import isqrt



1



Модератор

Эксперт функциональных языков программированияЭксперт Python

35328 / 19429 / 4065

Регистрация: 12.02.2012

Сообщений: 32,458

Записей в блоге: 13

16.04.2022, 11:10

15

eaa, да… Но интересно же сделать самому.



0



Status 418

Эксперт Python

3840 / 2124 / 568

Регистрация: 26.11.2017

Сообщений: 4,986

Записей в блоге: 2

16.04.2022, 11:40

16

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



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

35328 / 19429 / 4065

Регистрация: 12.02.2012

Сообщений: 32,458

Записей в блоге: 13

16.04.2022, 12:39

17

eaa, а есть более быстрые алгоритмы? Бин поиск – логарифмический.



0



Status 418

Эксперт Python

3840 / 2124 / 568

Регистрация: 26.11.2017

Сообщений: 4,986

Записей в блоге: 2

16.04.2022, 13:38

18

Catstail, если взять не икс пополам правую границу.

Добавлено через 51 минуту
проверил, оказывается нет разницы. но isqrt, в среднем работает в 3 раза быстрее.



1



Модератор

Эксперт функциональных языков программированияЭксперт Python

35328 / 19429 / 4065

Регистрация: 12.02.2012

Сообщений: 32,458

Записей в блоге: 13

16.04.2022, 14:00

19

eaa, а как он реализован? На Питоне?

Добавлено через 4 минуты
Есть еще идея – использовать классический метод Ньютона.



0



Status 418

Эксперт Python

3840 / 2124 / 568

Регистрация: 26.11.2017

Сообщений: 4,986

Записей в блоге: 2

16.04.2022, 14:37

20

модуль math, на си же.

Цитата
Сообщение от Catstail
Посмотреть сообщение

метод Ньютона

тот же бинпоиск.



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

16.04.2022, 14:37

Помогаю со студенческими работами здесь

Найти количество чисел, которые не превосходят числа A и являются полными квадратами некоторого натурального числа
Найти количество чисел, которые не превосходят числа A и являются полными квадратами некоторого…

Найти произведение чисел, которые не превосходят 4000 и являются полными квадратами некоторого натурального числа
Найти произведение чисел, которые не превосходят 4000 и являются полными квадратами некоторого…

Есть ли совершенные числа из промежутка [2, n], которые являются полными квадратами
Число называется совершенным, если равно сумме всех своих делителей, кроме
самого этого числа….

Найдите все числа, являющиеся полными квадратами, на отрезке от A до B
Найдите все числа на отрезке от A до B, являющиеся полными квадратами

Выведите все числа на отрезке от a до b, являющиеся полными квадратами
Вводятся целые числа a и b. Гарантируется, что a не превосходит b.
Выведите все числа на отрезке…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

20

Вы можете упростить арифметику, используя

(n + 1)**2 == n**2 + (2*n + 1)

Здесь, как это сделать, используя функцию генератора:

import math

def squares(lo, hi):
    root = int(math.ceil(lo ** 0.5))
    num = root ** 2
    delta = 2 * root + 1
    while num <= hi:
        yield num
        num += delta
        delta += 2

print list(squares(4, 16))
print list(squares(5, 50))
print list(squares(20, 90))

Выход

[4, 9, 16]
[9, 16, 25, 36, 49]
[25, 36, 49, 64, 81]

Здесь эквивалентный класс итератора. Я дал ему метод __repr__, поэтому он выглядит хорошо, если вы печатаете экземпляр этого класса.

import math

class Squares(object):
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop
        root = int(math.ceil(start ** 0.5))
        self.num = root ** 2
        self.delta = 2 * root + 1

    def __repr__(self):
        return 'Squares(%d, %d)' % (self.start, self.stop)

    def __iter__(self): 
        return self

    def next(self):
        num = self.num
        if num > self.stop:
            raise StopIteration
        self.num += self.delta
        self.delta += 2
        return num

sq = Squares(4, 16)
print sq
for i in sq:
    print i

print list(Squares(5, 50))
print list(Squares(20, 90))

Выход

Squares(4, 16)
4
9
16
[9, 16, 25, 36, 49]
[25, 36, 49, 64, 81]

Для Python 3 замените имя метода next на __next__.

Обычное соглашение Python range должно остановиться, прежде чем вы достигнете верхнего предела. Чтобы этот код соответствовал этому соглашению, в смене генератора squares()

while num <= hi:

to

while num < hi:

и в классе squares() измените

if num > self.stop:

to

if num >= self.stop:

Формулировка задачи:

Код к задаче: «Найти квадраты чисел, не превышающих 15»

textual

var i, a : integer;
begin
  i:=1;
  repeat
    a:=i;
    a:=sqr(a);
    Write(a, ' ');
    i:=i+1;
  until i>15;
end.

Полезно ли:

15   голосов , оценка 3.467 из 5

Вопрос:

Учитывая два числа x и y, найдите количество чисел, свободных от квадратов, где квадратное число равно делимому без идеального квадрата, кроме 1. Например, 10 является квадратным, но 18 не является, поскольку он делится на 9 = 32. Несколько положительных квадратов свободных чисел:

1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15 ...

пределы

1 <= X,Y <= 10^9

0 <= |X-Y| <= 10^6

x=10 , Y=15

дает

ans=5

Мой подход состоит в том, чтобы сгенерировать все простые до squareroot(10^9) (сито эратосфенов) и проверить, будет ли каждое число в заданном диапазоне делиться на квадрат простого числа. Граф таких чисел вычитается из длины диапазона, чтобы получить квадратные свободные числа.

Но этот подход требует сложной работы, пожалуйста, предложите другой подход

Лучший ответ:

Используйте принцип исключения включения:

Пусть f(n) = number of non-square-free numbers in 1 ... n. Мы будем делать исключение включения только на квадраты простых чисел, чтобы избежать перерасчета квадратов квадратов.

Имеем:

f(n) = n / 4      => these are divisible by 4, so NOT square-free
       +
       n / 9      => these are divisible by 9, so NOT square-free
       + 
       n / 25     => these are divisible by 16, so NOT square-free
       +
       ...
       -
       n / (4*9)  => these are divisible by both 4 and 9, so we overcounted
       -
       n / (4*25) => these are divisible by both 4 and 25, so we overcounted 
       -
       ...

Насколько это эффективно?

Нам нужны только числа p такие, что p^2 <= 10^9, что означает p < 31623. Это уже не много простых, любое тривиальное сито (или, может быть, даже пробное деление) должно быть достаточно быстрым. Затем примените включение-исключение, которое также будет быстрым, так как продукты квадратов простых чисел будут быстро развиваться, поэтому вы сможете завершить преждевременно во многих случаях (n / something = 0 всякий раз, когда something > n).

Чтобы понять, почему вы сможете досрочно прекратить работу, перепишите выше:

f(n) = n / (2^2) -
       n / (2^2*3^2) +
       n / (2^2*3^2*5^2) -  <= this becomes 0 very fast. 
                               When it does, 
                               backtrack and increment the previous term.
                               For example, if this were 0,
                               you'd do - n / (2^2*5^2) next
       ...

Подробнее об этом здесь.

Ответ №1

Чтобы развернуть мой комментарий: предположим, что X <= Y и инициализировать булевский массив SF [X..Y], чтобы быть истинным. Для каждого k от 2 до пола (sqrt (Y)) (необязательно включая композиты, асимптотическое время работы остается неизменным), для каждого кратного m k² между X и Y установите SF [m] в false. Верните количество истинных значений, оставшихся в SF.

Время работы O ((Y – X) + sqrt (Y)), так как Σ k = 1,…, ∞ 1/k² = π²/6.

Добавить комментарий