【C++进阶】完善Number类

举报
人才程序员 发表于 2024/09/14 18:05:06 2024/09/14
【摘要】 @TOC 前言在处理大整数运算时,标准的数据类型往往无法满足需求,因此需要设计一个能够处理任意大小整数的类。本文将介绍如何完善 Number 类,使其能够更高效地处理位操作和大整数运算。通过对类的构造函数、拷贝构造函数、赋值操作符和位操作方法进行实现和优化,我们可以创建一个功能强大且内存管理安全的 Number 类。 转换为小数在二进制的情况下,将一个数转为负数的过程因数据类型的不同(整数和...

@TOC


前言

在处理大整数运算时,标准的数据类型往往无法满足需求,因此需要设计一个能够处理任意大小整数的类。本文将介绍如何完善 Number 类,使其能够更高效地处理位操作和大整数运算。通过对类的构造函数、拷贝构造函数、赋值操作符和位操作方法进行实现和优化,我们可以创建一个功能强大且内存管理安全的 Number 类。


转换为小数

在二进制的情况下,将一个数转为负数的过程因数据类型的不同(整数和浮点数)而有所区别。主要区别在于其表示方式和处理方式。以下是对这两种情况的详细说明:

整数的二进制表示及取负

在计算机中,整数通常使用补码(Two’s Complement)表示负数。将一个二进制整数取负的方法如下:

  1. 取反(Bitwise NOT):将每一位(bit)都取反,即 0 变 1,1 变 0。
  2. 加一(Add 1):在取反的结果上加 1。

示例:

假设有一个 8 位的整数 5,其二进制表示为 00000101

  1. 取反11111010
  2. 加一11111010 + 1 = 11111011

结果 11111011 就是 -5 的补码表示。

浮点数的二进制表示及取负

浮点数使用 IEEE 754 标准表示,其主要分为三部分:符号位、指数位和尾数位。

  1. 符号位(Sign Bit):位于最左边,用于表示正负。0 表示正,1 表示负。
  2. 指数位(Exponent Bits):用于表示指数的部分。
  3. 尾数位(Mantissa Bits):用于表示尾数部分。

将浮点数取负的方法很简单,只需要将符号位取反即可。

示例:

假设有一个 32 位单精度浮点数 3.14,其二进制表示如下(IEEE 754 标准):

0 10000000 10010001111010111000011

这里:

  • 符号位:0
  • 指数位:10000000
  • 尾数位:10010001111010111000011

要将 3.14 变为 -3.14,只需要将符号位取反:

1 10000000 10010001111010111000011

结论

在二进制表示下,整数和浮点数取负数的过程有所不同:

  • 整数:使用补码表示,通过取反加一来实现。
  • 浮点数:使用 IEEE 754 标准表示,通过取反符号位来实现。

这两种表示方式的不同决定了它们在取负数时的操作方法有所区别。

所以我们需要不同情况不同处理

转换负数的实现

我们需要先定义一个枚举,表示当前类型,我们根据不同的类型进行不同的操作即可

enum Type
{
	Integer,
	FloatIngpoint,
	Undefine
};


Type NumberType;
void Number::ToNegative()
{
    if (NumberType == Type::Integer)
    {
        // 整数:使用补码表示负数
        // Invert all bits
        for (size_t i = 0; i < BitSize; ++i)
        {
            ToggleBit(i);
        }

        // Add 1 to the least significant bit
        bool carry = true;
        for (size_t i = 0; i < BitSize && carry; ++i)
        {
            if (GetBit(i) == 0)
            {
                SetBit(i);
                carry = false;
            }
            else
            {
                ClearBit(i);
            }
        }
    }
    else if (NumberType == Type::FloatIngpoint)
    {
        // 浮点数:取反符号位
        InvertSignBit();
    }
    else
    {
        throw std::runtime_error("Undefined number type");
    }
}

void Number::InvertSignBit()
{
    // 假设浮点数的符号位是最高位
    ToggleBit(BitSize - 1);
}

函数:ToNegative

功能: 将 Number 对象转换为其负数,具体根据 NumberType 的不同处理方式:

  1. 整数 (Type::Integer):

    • 步骤 1: 取反所有位
      • 使用 ToggleBit 函数对所有位进行取反操作。ToggleBit 函数会将每个位的值从 0 变成 1,或从 1 变成 0。
    • 步骤 2: 加 1
      • 对结果进行加 1 操作,这是一种将整数转换为负数的经典方法,即补码的表示方式。此步骤确保正确处理溢出并生成正确的负数表示。
      • 通过遍历每一位,利用 GetBit 函数获取当前位的值。如果位值为 0,则设置该位为 1 并停止加法操作。如果位值为 1,则清除该位,并继续处理下一位,直到完成加法操作。
  2. 浮点数 (Type::FloatIngpoint):

    • 步骤 1: 取反符号位
      • 使用 InvertSignBit 函数来切换浮点数的符号位。这是因为浮点数的符号位决定了其正负,取反符号位即可将其从正数转换为负数,或反之。
  3. 未定义类型 (else):

    • 如果 NumberType 既不是整数也不是浮点数,则抛出 std::runtime_error 异常,提示“Undefined number type”。

函数:InvertSignBit

功能: 将浮点数的符号位取反,具体实现如下:

  1. 符号位的假设:

    • 假设浮点数的符号位是二进制位序列中的最高位。
  2. 操作:

    • 使用 ToggleBit(BitSize - 1) 函数来切换符号位。BitSize - 1 表示最高位的索引。
    • ToggleBit 函数将该位的值从 0 变为 1,或从 1 变为 0,从而实现对符号位的取反。

实现+,-,*,/运算

实现add,multiply,divide函数

实现这几个函数是为了我们后面进行运算符重载

由于小数和整数的运算规律不同,所以我们可以把它变成虚函数,使子类进行实现他们不同的行为:

virtual void add(const Number& other, bool subtract) {};
virtual void multiply(const Number& other) {};
virtual void divide(const Number& other) {};

其中add函数的参数2表示是+还是-,+为false,-为true

实现他们的运算符重载

Number& operator+=(const Number& other);
Number& operator-=(const Number& other);
Number& operator*=(const Number& other);
Number& operator/=(const Number& other);
Number operator+(const Number& other) const;
Number operator-(const Number& other) const;
Number operator*(const Number& other) const;
Number operator/(const Number& other) const;

实现:

Number& Number::operator+=(const Number& other)
{
    add(other, false);
    return *this;
}

Number& Number::operator-=(const Number& other)
{
    add(other, true);
    return *this;
}

Number& Number::operator*=(const Number& other)
{
    multiply(other);
    return *this;
}

Number& Number::operator/=(const Number& other)
{
    divide(other);
    return *this;
}

Number Number::operator+(const Number& other) const
{
    Number result(*this);
    result += other;
    return result;
}

Number Number::operator-(const Number& other) const
{
    Number result(*this);
    result -= other;
    return result;
}

Number Number::operator*(const Number& other) const
{
    Number result(*this);
    result *= other;
    return result;
}

Number Number::operator/(const Number& other) const
{
    Number result(*this);
    result /= other;
    return result;
}

我们只需要调用上面我们实现的函数即可


总结

通过实现和完善 Number 类的各个成员函数,我们为处理大整数和位操作提供了一个强有力的工具。以下是我们在完善过程中完成的主要工作:

构造函数:负责分配内存和初始化数据,并处理可能的内存分配失败情况。
拷贝构造函数和赋值操作符:确保对象在复制和赋值时正确管理内存,避免内存泄漏和数据损坏。
位操作方法(SetBit, ClearBit, ToggleBit):提供对特定位的操作能力,确保位操作的准确性和效率。
通过这些实现,我们不仅提高了 Number 类的功能性和可靠性,还确保了内存管理的安全性。这样的设计和实现为大整数运算提供了坚实的基础,使其能够在各种应用场景中发挥重要作用。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。