c++的余数和整数

余数和指数

余数运算符(operator%)

余数运算符(通常也称为模运算符)是在进行整数除法后返回余数的运算符。

例如,7/4=1余数3。因此,7%4=3。另一个例子是,25/7=3余数4,因此25%7=4。余数运算符仅适用于整数操作数。

这对于测试一个数是否可以被另一个数整除(意味着在除法之后,没有余数)最有用:如果 x % y的计算结果为0,则我们知道x可以被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;
}

输入输出示例1

Enter an integer: 6
Enter another integer: 3
The remainder is: 0
6 is evenly divisible by 3
# 因为 6%3=0

输入输出示例2

Enter an integer: 6
Enter another integer: 4
The remainder is: 2
6 is not evenly divisible by 4
# 6%4=2

输入输出示例3

Enter an integer: 2
Enter another integer: 5
The remainder is: 2
2 is not evenly divisible by 5
# 2%5 = 2

带负数的余数

余数运算符也可以处理负操作数。 x % y总是返回带x符号的结果。

按照上述代码进行输入输出,示例为。

输入输出示例1

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

输入输出示例2

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

在这两种情况下,可以看到余数取第一个操作数的符号。

在第一个操作数可以为负的情况下,必须注意余数也可以为负。

是否为奇数的判断

编写一个函数来返回数字是否为奇数。

错误示范

bool isOdd(int x)
{
    return (x % 2) == 1; // 当x是 -5 时判断错误
}

然而,当x是负奇数时,这将判断错误,例如-5,因为-5%2是-1,并且-1!=1.

正确示范

因此,如果要比较余数运算的结果,最好与0进行比较,因为0没有正数/负数问题:

bool isOdd(int x)
{
    return (x % 2) != 0; // 或者可以写成 return (x % 2)
}

数学上的取模与取余

对于整型数a,b来说,取模运算或者求余运算的方法都是:

1.求整数商: c = [a/b];

2.计算模或者余数: r = a - c*b.

求模运算和求余运算在第一步不同:

  • 取余运算在取c的值时,向0 方向舍入(fix()函数);
  • 而取模运算在计算c的值时,向负无穷方向舍入(floor()函数)。

示例1

计算:-7 Mod 4,

那么:a = -7;b = 4;

  1. 第一步:求整数商c:

    ①进行求模运算时:c = [a/b] = -7 / 4 = -2(向负无穷方向舍入),
    
    ②进行求余运算时:c = [a/b] = -7 / 4 = -1(向0方向舍入);
    
  2. 第二步:计算模和余数的公式相同,但因c的值不同,

    ①求模时:r = a - c*b =-7 - (-2)*4 = 1,
    
    ②求余时:r = a - c*b = -7 - (-1)*4 =-3。
    

示例2

计算:7 Mod 4

那么:a = 7;b = 4

  1. 第一步:求整数商c:

    ①进行求模运算c = [a/b] = 7 / 4 = 1
    ②进行求余运算c = [a/b] = 7 / 4 = 1
    
  2. 第二步:计算模和余数的公式相同

    ①求模时:r = a - c*b =7 - (1)*4 = 3,
    ②求余时:r = a - c*b = 7 - (1)*4 =3

总结

归纳:当a和b正负号一致时,求模运算和求余运算所得的c的值一致,因此结果一致。

正负号不一致时,结果不一样。

尽管在c++中运算符%通常被称为“模”或“模”运算符,但它执行的实际上是取余的操作,因此,我们认为“余数”这个名称比“模”更准确地表示运算符%。

另外各个环境下%运算符的含义不同,比如c/c++,java 为取余,而python则为取模。

最佳实践

如果可能,最好将余数运算符(operator%)的结果与0进行比较。

指数运算符

pow方法

您会注意到^运算符(在数学中通常用于表示指数)是C++中的逐位异或运算。C++不包含指数运算符。

要在C++中执行指数,请 #include 标头,并使用 pow() 函数:

#include <cmath>

double x{ std::pow(3.0, 4.0) }; // 3的4次方

注意,函数pow() 的参数(和返回值)是double类型。由于浮点数中的舍入错误,pow() 的结果可能不精确(即使传递整数或整数)。

整数求幂函数的封装

基础版本

如果要进行整数求幂,最好使用自己的函数来完成。以下函数实现整数求幂(使用非直观的“平方求幂”算法以提高效率):

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

// note: exp 必须是非负整数
// note: 不执行越界检查
constexpr std::int64_t powint(std::int64_t base, int exp)
{
	assert(exp >= 0 && "powint: exp parameter has negative value");

	// 处理 base 为 0 的情况
	if (base == 0)
		return (exp == 0) ? 1 : 0;

	std::int64_t result{ 1 };
	while (exp > 0)
	{
		if (exp & 1)  // 如果exp 为奇数
			result *= base;
		exp /= 2;
		base *= base;
	}

	return result;
}

int main()
{
	std::cout << powint(7, 12) << '\n'; // 7 的 12 次方

	return 0;
}

输出结果

13841287201

constexpr标记允许编译器在编译时计算该函数。

优化版本

下面是上面检查溢出的指数函数的更安全版本:

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

// 一个更安全(但是稍慢) 的检查溢出的版本
// note: exp 必须是非负整数
// 如果发生越界,返回 std::numeric_limits<std::int64_t>::max()
constexpr std::int64_t powint_safe(std::int64_t base, int exp)
{
    assert(exp >= 0 && "powint_safe: exp parameter has negative value");

    // 处理 base 为 0 的情况
    if (base == 0)
        return (exp == 0) ? 1 : 0;

    std::int64_t result { 1 };

    // 为了确保越界更简单,将base调转为正数
    // 在返回结果时,再补上符号
    bool negativeResult{ false };

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

    while (exp > 0)
    {
        if (exp & 1) // 如果exp 为奇数
        {
            // 检查结果是否会溢出
            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 (exp <= 0)
            break;

        // 需要继续迭代,则继续执行检查

        // 检查结果是否会溢出
        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;
}

在绝大多数情况下,整数求幂将溢出整数类型。这可能就是为什么这样的函数最初没有包含在标准库中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值