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; // nie powiedzie się, gdy x wynosi -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 do potęgi czwartej

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> // dla potwierdzenia
#include <cstdint> // dla std::int64_t
#include <iostream>

// uwaga: exp musi być nieujemna
// uwaga: nie sprawdza zakresu/przepełnienia, używaj ostrożnie
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)  // jeśli exp jest nieparzysty
			result *= base;
		exp /= 2;
		base *= base;
	}

	return result;
}

int main()
{
	std::cout << powint(7, 12) << '\n'; // 7 do potęgi 12

	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> // dla potwierdzenia
#include <cstdint> // dla std::int64_t
#include <iostream>
#include <limits> // dla std::numeric_limits

// Bezpieczniejsza (ale wolniejsza) wersja powint(), która sprawdza przepełnienie
// uwaga: exp musi być nieujemna
// Zwraca std::numeric_limits<std::int64_t>::max() w przypadku przepełnienia występuje
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 };

    // Aby ułatwić sprawdzanie zakresu, upewnimy się, że podstawa jest dodatnia
    // W razie potrzeby odwrócimy wynik na końcu
    bool negativeResult{ false };

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

    while (exp > 0)
    {
        if (exp & 1) // jeśli exp jest nieparzysty
        {
            // Sprawdź, czy wynik będzie przepełniony przy pomnożeniu przez podstawę
            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;

        // Jeśli skończyliśmy, wyjdź tutaj
        if (exp <= 0)
            break;

        // Wymagane są tylko poniższe wiersze do wykonania, jeśli mamy zamiar powtórzyć iterację

        // Sprawdź, czy baza tak przepełnienie przy mnożeniu przez podstawę
        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 do potęgi 12
	std::cout << powint_safe(70, 12) << '\n'; // 70 do potęgi 12 (zwróci maksymalną 64-bitową wartość int)

	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