【C++进阶】完善Number类
@TOC
前言
在处理大整数运算时,标准的数据类型往往无法满足需求,因此需要设计一个能够处理任意大小整数的类。本文将介绍如何完善 Number 类,使其能够更高效地处理位操作和大整数运算。通过对类的构造函数、拷贝构造函数、赋值操作符和位操作方法进行实现和优化,我们可以创建一个功能强大且内存管理安全的 Number 类。
转换为小数
在二进制的情况下,将一个数转为负数的过程因数据类型的不同(整数和浮点数)而有所区别。主要区别在于其表示方式和处理方式。以下是对这两种情况的详细说明:
整数的二进制表示及取负
在计算机中,整数通常使用补码(Two’s Complement)表示负数。将一个二进制整数取负的方法如下:
- 取反(Bitwise NOT):将每一位(bit)都取反,即 0 变 1,1 变 0。
- 加一(Add 1):在取反的结果上加 1。
示例:
假设有一个 8 位的整数 5,其二进制表示为 00000101
。
- 取反:
11111010
- 加一:
11111010 + 1 = 11111011
结果 11111011
就是 -5 的补码表示。
浮点数的二进制表示及取负
浮点数使用 IEEE 754 标准表示,其主要分为三部分:符号位、指数位和尾数位。
- 符号位(Sign Bit):位于最左边,用于表示正负。0 表示正,1 表示负。
- 指数位(Exponent Bits):用于表示指数的部分。
- 尾数位(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
的不同处理方式:
-
整数 (
Type::Integer
):- 步骤 1: 取反所有位
- 使用
ToggleBit
函数对所有位进行取反操作。ToggleBit
函数会将每个位的值从 0 变成 1,或从 1 变成 0。
- 使用
- 步骤 2: 加 1
- 对结果进行加 1 操作,这是一种将整数转换为负数的经典方法,即补码的表示方式。此步骤确保正确处理溢出并生成正确的负数表示。
- 通过遍历每一位,利用
GetBit
函数获取当前位的值。如果位值为 0,则设置该位为 1 并停止加法操作。如果位值为 1,则清除该位,并继续处理下一位,直到完成加法操作。
- 步骤 1: 取反所有位
-
浮点数 (
Type::FloatIngpoint
):- 步骤 1: 取反符号位
- 使用
InvertSignBit
函数来切换浮点数的符号位。这是因为浮点数的符号位决定了其正负,取反符号位即可将其从正数转换为负数,或反之。
- 使用
- 步骤 1: 取反符号位
-
未定义类型 (
else
):- 如果
NumberType
既不是整数也不是浮点数,则抛出std::runtime_error
异常,提示“Undefined number type”。
- 如果
函数:InvertSignBit
功能: 将浮点数的符号位取反,具体实现如下:
-
符号位的假设:
- 假设浮点数的符号位是二进制位序列中的最高位。
-
操作:
- 使用
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 类的功能性和可靠性,还确保了内存管理的安全性。这样的设计和实现为大整数运算提供了坚实的基础,使其能够在各种应用场景中发挥重要作用。
- 点赞
- 收藏
- 关注作者
评论(0)