Я могу полагаться на это для оценки квадратного числа в C++?

ipGlobalProperties.GetActiveTcpConnections() не возвращается, соединения в Слушают состояние.

Порт может использоваться для слушания, но без одного связанного с ним выше не будет работать метод, описанный.

5
задан Kyle Walsh 9 September 2009 в 16:32
поделиться

12 ответов

На самом деле, это не C ++, а математический вопрос.

  1. При работе с числами с плавающей запятой никогда не следует полагаться на равенство. Если вы должны протестировать a == b, просто протестируйте против abs (a - b)
  2. Если число, которое вы are testing - целое число, вас может заинтересовать статья в Википедии о Целочисленный квадратный корень

РЕДАКТИРОВАТЬ:

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

Для нетерпеливых есть ссылка в статье на подробное обсуждение реализации isqrt ].

15
ответ дан 18 December 2019 в 06:51
поделиться

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

Isqrt взят из здесь и является O (log n)

// Finds the integer square root of a positive number
static int Isqrt(int num)
{
    if (0 == num) { return 0; }  // Avoid zero divide
    int n = (num / 2) + 1;       // Initial estimate, never low
    int n1 = (n + (num / n)) / 2;
    while (n1 < n)
    {
        n = n1;
        n1 = (n + (num / n)) / 2;
    } // end while
    return n;
} // end Isqrt()

static bool IsPerfectSquare(int num)
{
    return Isqrt(num) * Isqrt(num) == num;
}
5
ответ дан 18 December 2019 в 06:51
поделиться

Чтобы не делать один и тот же расчет дважды, я бы сделал это с временным номером:

 int b = (int)sqrt((float)a);
 if((b*b) == a)
 {
     //perfect square
 }

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

, поэтому оно должно быть:

 int b = (int) (sqrt((float)a) + 0.5f);
 if((b*b) == a)
 {
     //perfect square
 }
2
ответ дан 18 December 2019 в 06:51
поделиться

На ваш вопрос уже был дан ответ, но вот рабочее решение.

Ваши «идеальные квадраты» неявно являются целочисленными значениями, поэтому вы можете легко решить проблемы точности, связанные с форматом с плавающей запятой, используя некоторая функция квадратного корня целого числа для определения квадратного корня целого числа из значения, которое вы хотите проверить. Эта функция вернет наибольшее число r для значения v , где r * r <= v . Когда у вас есть r , вам просто нужно проверить, r * r == v .

unsigned short isqrt (unsigned long a)
{
    unsigned long rem = 0;
    unsigned long root = 0;

    for (int i = 16; i; i--) {
        root <<= 1;
        rem = ((rem << 2) + (a >> 30));
        a <<= 2;
        if (root < rem)
            rem -= ++root;
    }

    return (unsigned short) (root >> 1);
}

bool PerfectSquare (unsigned long a)
{
    unsigned short r = isqrt (a);

    return r * r == a;
}
2
ответ дан 18 December 2019 в 06:51
поделиться

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

bool isSquare(long val) {
    double root = sqrt(val);
    if (root == (long) root)
        return true;
    else return false;
}

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

1
ответ дан 18 December 2019 в 06:51
поделиться

сначала основы:

if вы (int) число в вычислении удалит ВСЕ данные после запятой. Если я правильно помню свой C, если у вас есть (int) в любом вычислении (+ / - *), он автоматически будет предполагать int для всех других чисел.

Итак, в вашем случае вы хотите float для каждого задействованного числа, иначе вы потеряет данные:

-2
ответ дан 18 December 2019 в 06:51
поделиться

Математика с плавающей запятой по своей природе неточна.

Рассмотрим этот код:

int a=35;
float conv = (float)a;
float sqrt_a = sqrt(conv);
if( sqrt_a*sqrt_a == conv )
    printf("perfect square");

вот что произойдет:

a = 35
conv = 35.000000
sqrt_a = 5.916079
sqrt_a*sqrt_a = 34.999990734

совершенно ясно, что sqrt_a ^ 2 не равно А.

-2
ответ дан 18 December 2019 в 06:51
поделиться

Я бы сделал.

// sqrt always returns positive value. So casting to int is equivalent to floor()
int down =  static_cast<int>(sqrt(value));
int up   = down+1;                           // This is the ceil(sqrt(value))

// Because of rounding problems I would test the floor() and ceil()
// of the value returned from sqrt().
if (((down*down) == value) || ((up*up) == value))
{
     // We have a winner.
}
1
ответ дан 18 December 2019 в 06:51
поделиться

Как говорит Райниер, вам нужно добавить 0,5, чтобы обеспечить округление до ближайшего целого числа, поэтому вы получите

int b = (int) (sqrt((float)a) + 0.5f);
if((b*b) == a) /* perfect square */

Чтобы это сработало, b должно быть (точно) равно квадратному корню из a , если a - полный квадрат. Однако я не думаю, что это можно гарантировать. Предположим, что int составляет 64 бита, а float - 32 бита (я думаю, что это разрешено). Тогда a может иметь порядок 2 ^ 60, поэтому его квадратный корень имеет порядок 2 ^ 30. Однако float хранит только 24 бита в мантиссе, поэтому ошибка округления имеет порядок 2 ^ (30-24) = 2 ^ 6. Это больше 1, поэтому b может содержать неправильное целое число. Например, я думаю, что приведенный выше код не идентифицирует a = (2 ^ 30 + 1) ^ 2 как полный квадрат.

1
ответ дан 18 December 2019 в 06:51
поделиться

Более очевидный, если медленнее - O (sqrt (n)) - способ:

bool is_perfect_square(int i) {
    int d = 1;
    for (int x = 0; x <= i; x += d, d += 2) {
        if (x == i) return true;
    }
    return false;   
}
0
ответ дан 18 December 2019 в 06:51
поделиться

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

b = sqrt((float)a)
b - floor(b) < e

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

Квадратное число может заканчиваться только на digits 00,1,4,6,9, or 25 in base 10

Another simple check would be to see that a % 4 == 1 or 0 before taking the root since:

Squares of even numbers are even, since (2n)^2 = 4n^2.
Squares of odd numbers are odd, since (2n + 1)^2 = 4(n^2 + n) + 1.

These would essentially eliminate half of the integers before taking any roots.

0
ответ дан 18 December 2019 в 06:51
поделиться

Самое чистое решение - использовать целочисленную подпрограмму sqrt, а затем выполнить:

bool isSquare( unsigned int a ) {

  unsigned int s = isqrt( a );
  return s * s == a;

}

Это будет работать в полном диапазоне int и с идеальной точностью. Несколько случаев:

a = 0, s = 0, s * s = 0 (add an exception if you don't want to treat 0 as square)  
a = 1, s = 1, s * s = 1  
a = 2, s = 1, s * s = 1  
a = 3, s = 1, s * s = 1  
a = 4, s = 2, s * s = 4  
a = 5, s = 2, s * s = 4

Не потерпит неудачу, когда вы приблизитесь к максимальному значению для вашего размера int. Например, для 32-битных целых чисел:

a = 0x40000000, s = 0x00008000, s * s = 0x40000000  
a = 0xFFFFFFFF, s = 0x0000FFFF, s * s = 0xFFFE0001

Используя числа с плавающей запятой, вы можете столкнуться с рядом проблем. Вы можете обнаружить, что sqrt (4) = 1.999999 ... , и аналогичные проблемы, хотя вы можете округлить до ближайшего вместо использования floor () .

Хотя хуже , float имеет только 24 значащих бита, что означает, что вы не можете преобразовать int больше 2 ^ 24-1 в float без потери точности, что приводит к ложным срабатываниям / отрицаниям. Однако с использованием удвоений для тестирования 32-битных целых чисел все будет в порядке.

Но не забудьте вернуть результат sqrt с плавающей запятой обратно в int и сравнить результат с исходным int. Сравнение поплавков никогда не бывает хорошей идеей; даже для квадратных значений x в ограниченном диапазоне нет гарантии, что sqrt (x) * sqrt (x) == x или что sqrt (x * x) = x .

0
ответ дан 18 December 2019 в 06:51
поделиться
Другие вопросы по тегам:

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