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 czwartejZauważ, ż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 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.
Twój program powinien odpowiadać następującym wynikom:
Enter an integer: 5 5 is odd

