6.3 -- Reszta i potęgowanie

Operator reszty (operator%)

Klasa operator reszty (powszechnie nazywany również operatorem modulo lub modulus operator) to operator, który zwraca resztę po podzieleniu liczb całkowitych. Na przykład 7 / 4 = 1 reszta 3. Zatem 7% 4 = 3. W innym przykładzie 25 / 7 = 3 reszta 4, czyli 25% 7 = 4. Operator reszty działa tylko z operandami całkowitymi.

Jest to najbardziej przydatne do sprawdzania, czy liczba jest parzysta. jest podzielny przez inną liczbę (co oznacza, że po dzieleniu nie ma reszty): jeśli x % y wyniesie 0, to wiemy, że x jest równomiernie podzielny przez y.

#include <iostream>

int main()
{
	std::cout << "Enter an integer: ";
	int x{};
	std::cin >> x;

	std::cout << "Enter another integer: ";
	int y{};
	std::cin >> y;

	std::cout << "The remainder is: " << x % y << '\n';

	if ((x % y) == 0)
		std::cout << x << " is evenly divisible by " << y << '\n';
	else
		std::cout << x << " is not evenly divisible by " << y << '\n';

	return 0;
}

Oto kilka przebiegów tego programu:

Enter an integer: 6
Enter another integer: 3
The remainder is: 0
6 is evenly divisible by 3
Enter an integer: 6
Enter another integer: 4
The remainder is: 2
6 is not evenly divisible by 4

Wypróbujmy teraz przykład, w którym druga liczba jest większa od pierwszej:

Enter an integer: 2
Enter another integer: 4
The remainder is: 2
2 is not evenly divisible by 4

Reszta z 2 może być na początku trochę nieoczywiste, ale to proste: 2 / 4 to 0 (przy dzieleniu całkowitym) reszta 2. Ilekroć druga liczba jest większa od pierwszej, druga liczba podzieli pierwsze 0 razy, więc pierwsza liczba będzie resztą.

Reszta z liczbami ujemnymi

Operator reszty może również działać z argumentami ujemnymi. x % y zawsze zwraca wyniki znak x.

Uruchomienie powyższego programu:

Enter an integer: -6
Enter another integer: 4
The remainder is: -2
-6 is not evenly divisible by 4
Enter an integer: 6
Enter another integer: -4
The remainder is: 2
6 is not evenly divisible by -4

W obu przypadkach widać, że reszta przyjmuje znak pierwszego operandu.

Nomenklatura

Standard C++ tak naprawdę nie podaje nazwy dla operator% Jednak standard C++20 mówi, że „binarny operator % daje resztę z dzielenia pierwszego wyrażenia przez sekunda”.

Chociaż operator% jest często nazywany operatorem „modulo” lub „modulus”, może to być mylące, ponieważ modulo w matematyce jest często definiowane w sposób, który daje inny wynik niż ten, który operator% w C++ daje, gdy jeden (i tylko jeden) z operandów jest ujemny.

Na przykład w matematyce:
-21 modulo 4 = 3
-21 reszta 4 = -1

Z tego powodu uważamy, że nazwa „reszta” jest bardziej dokładną nazwą dla operator% niż „modulo”.

W przypadkach, gdy pierwszy operand może być ujemny, należy pamiętać, że reszta może być również ujemna. Można na przykład pomyśleć o napisaniu funkcji, która zwraca, czy liczba jest nieparzysta to:

bool isOdd(int x)
{
    return (x % 2) == 1; // fails when x is -5
}

To jednak nie powiedzie się, gdy x jest ujemną liczbą nieparzystą, na przykład -5, ponieważ -5 % 2 jest -1 i -1 != 1.

Z tego powodu, jeśli zamierzasz porównać wynik operacji reszty, lepiej porównać z 0, które nie ma problemów z liczbami dodatnimi/ujemnymi:

bool isOdd(int x)
{
    return (x % 2) != 0; // could also write return (x % 2)
}

Najlepsza praktyka

Wolę porównać wynik reszty operator (operator%) względem 0, jeśli to możliwe.

Gdzie jest operator wykładnika?

Zauważysz, że operator ^ (powszechnie używany do oznaczania potęgowania w matematyce) to Bitowego XOR operacja w C++ (opisana w lekcji O.3 -- Manipulacja bitami za pomocą operatorów bitowych i bitów masks). C++ nie zawiera operatora wykładnika.

Aby wykonać wykładniki w C++, #dołącz nagłówek <cmath> i użyj funkcji pow():

#include <cmath>

double x{ std::pow(3.0, 4.0) }; // 3 to the 4th power

Zauważ, że parametry (i zwracana wartość) funkcji pow() są typu double Ze względu na błędy zaokrąglania liczb zmiennoprzecinkowych wyniki pow() mogą nie być dokładne (nawet jeśli przekażesz je jako liczby całkowite). lub liczby całkowite).

Jeśli chcesz dokonać potęgowania liczb całkowitych, najlepiej użyj do tego własnej funkcji. Następująca funkcja implementuje potęgowanie liczb całkowitych (w celu zwiększenia wydajności wykorzystuje nieintuicyjny algorytm „potęgowania przez podniesienie”):

#include <cassert> // for assert
#include <cstdint> // for std::int64_t
#include <iostream>

// note: exp must be non-negative
// note: does not perform range/overflow checking, use with caution
constexpr std::int64_t powint(std::int64_t base, int exp)
{
	assert(exp >= 0 && "powint: exp parameter has negative value");

	// Handle 0 case
	if (base == 0)
		return (exp == 0) ? 1 : 0;

	std::int64_t result{ 1 };
	while (exp > 0)
	{
		if (exp & 1)  // if exp is odd
			result *= base;
		exp /= 2;
		base *= base;
	}

	return result;
}

int main()
{
	std::cout << powint(7, 12) << '\n'; // 7 to the 12th power

	return 0;
}

Produkuje:

13841287201

Nie martw się, jeśli nie rozumiesz, jak działa ta funkcja – nie musisz jej rozumieć w języku aby go wywołać.

Powiązana treść

Afirmacje omówimy na lekcji 9.6 — Assert i static_assert, a funkcje constexpr na lekcji F.1 -- Funkcje Constexpr.

Dla zaawansowanych czytelników

Klasa constexpr umożliwia ocenę funkcji w czasie kompilacji, jeśli jest używana w wyrażeniu stałym; w przeciwnym razie zachowuje się jak zwykła funkcja i jest oceniana w czasie wykonywania.

Ostrzeżenie

W zdecydowanej większości przypadków potęgowanie liczb całkowitych przepełni typ całkowity. Prawdopodobnie z tego właśnie powodu taka funkcja nie została uwzględniona w bibliotece standardowej.

Oto bezpieczniejsza wersja powyższej funkcji potęgowania, która sprawdza przepełnienie:

#include <cassert> // for assert
#include <cstdint> // for std::int64_t
#include <iostream>
#include <limits> // for std::numeric_limits

// A safer (but slower) version of powint() that checks for overflow
// note: exp must be non-negative
// Returns std::numeric_limits<std::int64_t>::max() if overflow occurs
constexpr std::int64_t powint_safe(std::int64_t base, int exp)
{
    assert(exp >= 0 && "powint_safe: exp parameter has negative value");

    // Handle 0 case
    if (base == 0)
        return (exp == 0) ? 1 : 0;

    std::int64_t result { 1 };

    // To make the range checks easier, we'll ensure base is positive
    // We'll flip the result at the end if needed
    bool negativeResult{ false };

    if (base < 0)
    {
        base = -base;
        negativeResult = (exp & 1);
    }

    while (exp > 0)
    {
        if (exp & 1) // if exp is odd
        {
            // Check if result will overflow when multiplied by base
            if (result > std::numeric_limits<std::int64_t>::max() / base)
            {
                std::cerr << "powint_safe(): result overflowed\n";
                return std::numeric_limits<std::int64_t>::max();
            }

            result *= base;
        }

        exp /= 2;

        // If we're done, get out here
        if (exp <= 0)
            break;

        // The following only needs to execute if we're going to iterate again

        // Check if base will overflow when multiplied by base
        if (base > std::numeric_limits<std::int64_t>::max() / base)
        {
            std::cerr << "powint_safe(): base overflowed\n";
            return std::numeric_limits<std::int64_t>::max();
        }

        base *= base;
    }

    if (negativeResult)
        return -result;

    return result;
}

int main()
{
	std::cout << powint_safe(7, 12) << '\n'; // 7 to the 12th power
	std::cout << powint_safe(70, 12) << '\n'; // 70 to the 12th power (will return the max 64-bit int value)

	return 0;
}

Czas quizu

Pytanie nr 1

Co oznacza poniższe wyrażenie? 6 + 5 * 4 % 3

Pokaż rozwiązanie

Pytanie nr 2

Napisz program, który poprosi użytkownika o wprowadzenie liczby całkowitej i poinformuje użytkownika, czy liczba ta jest parzysta czy nieparzysta. Napisz funkcję constexpr o nazwie isEven() , która zwraca wartość true, jeśli przekazana do niej liczba całkowita jest parzysta, lub false w przeciwnym razie. Użyj operatora reszty, aby sprawdzić, czy parametr całkowity jest parzysty. Upewnij się, że isEven() działa zarówno z liczbami dodatnimi, jak i ujemnymi.

Pokaż wskazówkę

Twój program powinien odpowiadać następującym wynikom:

Enter an integer: 5
5 is odd

Pokaż rozwiązanie

guest
Twój adres e-mail nie zostanie wyświetlony
Znalazłeś błąd? Zostaw komentarz powyżej!
Komentarze związane z poprawkami zostaną usunięte po przetworzeniu, aby pomóc zmniejszyć bałagan. Dziękujemy za pomoc w ulepszaniu witryny dla wszystkich!
Awatary z https://gravatar.com/ są połączone z podanym adresem e-mail.
Powiadamiaj mnie o odpowiedziach:  
489 Komentarze
Najnowsze
Najstarsze Najczęściej głosowane
Wbudowane opinie
Wyświetl wszystkie komentarze