How C++ Represents Negative Values

Mohd Mohtashim Nawaz Oct 26, 2023
  1. Sign-and-Magnitude Representation for Negative Values in C++
  2. Two’s Complement Representation for Negative Values in C++
  3. One’s Complement Representation for Negative Values in C++
  4. Excess-k Representation for Negative Values in C++
  5. Negative Integer of Maximum Magnitude Using Bit Shifting in C++
  6. Conclusion
How C++ Represents Negative Values

Negative value representation is a fundamental concept in computer programming, especially when working with numeric data types. In C++, there are several methods used to represent negative values.

In this article, we will delve into these methods, providing detailed explanations and an example code for each. Understanding how negative values are represented in C++ is crucial for performing arithmetic operations, bitwise operations, and other mathematical computations.

There is no rule for representing negative values in C++. Therefore, users can choose their implementation details to represent a negative value.

However, there are four common methods for representing negative numbers. Let’s look at each one of them below.

Sign-and-Magnitude Representation for Negative Values in C++

Sign-and-magnitude representation is one of the simplest ways to represent C++ negative numbers. In this method, a sign bit is used to indicate whether the number is positive or negative, while the remaining bits represent the magnitude of the number.

In Sign-and-Magnitude representation, a fixed number of bits are allocated to represent a numeric value. Among these bits, the most significant bit (MSB) is reserved as the sign bit, while the rest are used to represent the magnitude of the number.

  • The sign bit:
    • 0: Represents a positive number.
    • 1: Represents a negative number.
  • The magnitude bits:
    • Used to represent the absolute value of the number.

However, this method has serious problems when implemented in computers, especially while performing arithmetic operations on negative numbers.

Range of Representable Values

The range of representable values in Sign-and-Magnitude representation is slightly different from the more commonly used Two’s Complement system. In an n-bit Sign-and-Magnitude system, you can represent values from -2(n-1) + 1 to 2(n-1) - 1.

For example, in an 8-bit representation, you can represent values from -127 to 127.

Sign-and-Magnitude in C++

Let’s demonstrate how Sign-and-Magnitude representation can be implemented in C++.

#include <iostream>
#include <bitset>
using namespace std;

// Function to convert an integer to Sign-and-Magnitude representation
string intToSignMagnitude(int num, int bits) {
    string signMag = (num < 0) ? "1" : "0"; // Set the sign bit
    num = abs(num); // Get absolute value for magnitude
    string magnitude = bitset<7>(num).to_string(); // Convert magnitude to binary
    return signMag + magnitude;
}

// Function to convert Sign-and-Magnitude representation to integer
int signMagnitudeToInt(string signMag) {
    int sign = (signMag[0] == '1') ? -1 : 1; // Determine sign
    signMag = signMag.substr(1); // Remove sign bit
    int magnitude = stoi(signMag, nullptr, 2); // Convert binary to decimal
    return sign * magnitude; // Apply sign to magnitude
}

int main() {
    int num = -27;
    int bits = 7;

    string signMagnitude = intToSignMagnitude(num, bits);
    int convertedNum = signMagnitudeToInt(signMagnitude);

    cout << "Original Number: " << num << endl;
    cout << "Sign-and-Magnitude: " << signMagnitude << endl;
    cout << "Converted Number: " << convertedNum << endl;

    return 0;
}

This code demonstrates a program for converting between integers and the Sign-and-Magnitude representation. It defines two functions: intToSignMagnitude and signMagnitudeToInt.

intToSignMagnitude converts an integer to a Sign-and-Magnitude representation. It determines the sign bit (1 for negative, 0 for positive), computes the absolute value for magnitude, converts the magnitude to binary, and returns the combined representation.

signMagnitudeToInt converts the Sign-and-Magnitude representation back to an integer. It extracts the sign, removes the sign bit, converts the magnitude from binary to decimal, applies the sign, and returns the integer.

In the main function, a test case with num = -27 and bits = 7 is used. The program then demonstrates the conversion process and prints the original number, the Sign-and-Magnitude representation, and the converted number.

Output:

Original Number: -27
Sign-and-Magnitude: 10011011
Converted Number: -27

Two’s Complement Representation for Negative Values in C++

Two’s complement representation is the most widely used method for representing C++ negative numbers in modern computers. In this method, the sign bit is also used to indicate the sign of the number.

However, the magnitude is represented in a way that allows for efficient addition and subtraction operations.

In this method, a sign bit is fixed to represent the sign. If a negative number is encountered, its bit representation is calculated. After that, the bits are flipped, and 1 is added to them.

Let us see an example:

Number: -6
Sign: -ve so sign bit = 1
Bitwise representation of 6: 000110
Two's complement: 111001+1 = 111010
So the number is represented as 1111010

This method overcomes the shortcomings of one’s complement method.

The Sign Bit

In Two’s Complement, the leftmost bit is used as the sign bit. If this bit is 0, the number is positive; if it’s 1, the number is negative. The remaining bits represent the magnitude of the number.

For instance:

  • 0110 represents +6
  • 1010 represents -6

Positive Numbers

Representing positive numbers in Two’s Complement is straightforward. The sign bit is set to 0, and the remaining bits are used to represent the magnitude.

Negative Numbers

To represent negative numbers, Two’s Complement employs a clever technique. The negation of a number x in Two’s Complement is achieved by inverting all the bits (changing 0s to 1s and vice versa) and then adding 1.

For example, to represent -6 in a 4-bit Two’s Complement system, we need to start with the binary representation of 6: 0110.

Then, we invert all the bits: 1001. Finally, we add 1: 1010.

The code below implements the steps described above to represent a number in a 4-bit Two’s Complement system.

#include <iostream>
using namespace std;

// Function to get the 4-bit Two's Complement representation
string twosComplement(int num) {
    // Step 1: Get the binary representation of the absolute value
    string binary = "";
    for (int i = 0; i < 4; i++) {
        binary = to_string(num % 2) + binary;
        num /= 2;
    }

    // Step 2: Invert all the bits
    for (char &bit : binary) {
        bit = (bit == '0') ? '1' : '0';
    }

    // Step 3: Add 1
    int carry = 1;
    for (int i = 3; i >= 0; i--) {
        if (binary[i] == '1' && carry == 1) {
            binary[i] = '0';
        } else if (binary[i] == '0' && carry == 1) {
            binary[i] = '1';
            carry = 0;
        }
    }

    return binary;
}

int main() {
    int num = -6;

    string result = twosComplement(abs(num));

    cout << "The 4-bit Two's Complement representation of " << num << " is: " << result << endl;

    return 0;
}

This code defines a function called twosComplement that converts a given decimal number into its 4-bit Two’s Complement representation. The function takes an integer as input and performs three steps.

First, it converts the absolute value of the input number into binary. Next, it inverts all the bits in the binary representation.

Lastly, it simulates the process of adding 1 to the inverted binary representation.

In the main function, the code applies this process to the number -6. The resulting 4-bit Two’s Complement representation is displayed along with the original decimal input.

Output:

The 4-bit Two's Complement representation of -6 is: 1010

One’s Complement Representation for Negative Values in C++

One’s complement representation is similar to two’s complement, but the method of obtaining the negative representation differs. In this method, the sign bit is still used to indicate the sign of the number, and the magnitude is represented using one’s complement.

In this method, the most significant bit (leftmost bit) represents the sign of the number. If the sign bit is 0, the number is positive; if it’s 1, the number is negative.

For example, in an 8-bit system, the number 01100101 would be interpreted as a positive integer. The leading 0 indicates a positive sign.

In the One’s Complement system, to represent a negative number, you invert (flip) all the bits of the positive form of that number. For example, to represent -5 in an 8-bit system, you start with the binary representation of 5:

Positive:  00000101

Then, you invert all the bits (change the 0s to 1s and 1s to 0s):

Negative: 11111010

This representation might seem counterintuitive at first glance, but it has some advantages in certain operations, such as addition and subtraction.

The code below demonstrates how One’s Complement representation can be implemented in C++.

#include <iostream>
using namespace std;

// Function to convert integer to 8-bit binary string
string intToBinary(int num) {
    string binary = "";
    while (num > 0) {
        binary = to_string(num % 2) + binary;
        num /= 2;
    }
    while (binary.length() < 8) {
        binary = "0" + binary;
    }
    return binary;
}

// Function to perform One's Complement
string onesComplement(int num) {
    string binary = intToBinary(num);
    string complement = "";

    for (char bit : binary) {
        if (bit == '0') {
            complement += '1';
        } else {
            complement += '0';
        }
    }

    return complement;
}

int main() {
    int num = -5; // Negative number
    string complementedBinary = onesComplement(-num); // Invert the bits

    cout << "Original number: " << num << " (binary: " << intToBinary(-num) << ")" << endl;
    cout << "One's Complement representation: " << complementedBinary << endl;

    return 0;
}

This code demonstrates the process of obtaining the One’s Complement representation of a given integer. It defines two functions: intToBinary and onesComplement.

intToBinary converts an integer into an 8-bit binary string by repeatedly dividing the number by 2 and appending the remainder to the binary string. It ensures the string is 8 bits long.

onesComplement calculates the One’s Complement of a number by inverting each bit in its binary representation.

In the main function, it applies these functions to find the One’s Complement of -5. The output displays the original number, its binary representation, and the One’s Complement representation.

Output:

Original number: -5 (binary: 00000101)
One's Complement representation: 11111010

Excess-k Representation for Negative Values in C++

Excess-k representation, also known as biased representation, is a method to represent both positive and negative numbers in binary form.

The key concept is to add a bias (k) to the actual value before converting it to binary. This bias is chosen such that the most negative value will be represented as 0...0 and the most positive value as 1...1.

Example:

#include <iostream>
using namespace std;

string toExcessK(int num, int k) {
    num += k; // Add the bias
    string binary = "";
    while (num > 0) {
        binary = to_string(num % 2) + binary;
        num /= 2;
    }
    while (binary.length() < 4) {
        binary = "0" + binary; // Ensure a fixed length of 4 bits
    }
    return binary;
}

int main() {
    int num = -3; // Input number
    int k = 7; // Bias for Excess-k representation

    string excessK = toExcessK(num, k);

    cout << "Original number: " << num << endl;
    cout << "Excess-" << k << " representation: " << excessK << endl;

    return 0;
}

This code snippet defines a function toExcessK that converts a given integer num into its Excess-K representation, using a bias k. The Excess-K representation is obtained by adding the bias k to the input number num, converting the result to binary, and ensuring a fixed length of 4 bits.

In the main function, an example is provided where -3 is used as the input number and 7 is chosen as the bias for Excess-7 representation. The program outputs:

Original number: -3
Excess-7 representation: 0100

Negative Integer of Maximum Magnitude Using Bit Shifting in C++

You can get the maximum value of the integer data type by shifting the bits so that all bits except the sign bit are 1.

You have an 8-bit integer representation (for example only). The representation of -1 is as given below.

Number: -1
Sign: -ve so sign bit = 1
Bitwise representation of 1: 000 0001
Two's complement: 111 1110 + 1 = 111 1111
So -1 is represented as 1111 1111.

If you left-shift -1 by one place, its binary representation becomes 0111 1111.

This represents the maximum number. You can obtain the smallest negative number (minimum value) by simply reversing the bits.

Let us see the code:

#include <iostream>

using namespace std;

int getLargest() {
  int num = -1u >> 1;
  return num;
}

int getSmallest() {
  int num = -1u >> 1;
  num = ~num;

  return num;
}

int main() {
  cout << "Maximum value: " << getLargest() << endl;
  cout << "Minimum value:" << getSmallest() << endl;
  return 0;
}

This code aims to find the maximum and minimum values representable by the integer data type using bitwise operations.

The getLargest() function calculates the largest signed integer value by performing a right shift operation on the maximum unsigned integer value. This effectively halves the value and assigns it to the variable num.

In the getSmallest() function, a similar approach is used to obtain the largest signed integer value, which is then bitwise negated to obtain the smallest representable value for a signed integer.

In the main() function, the results are printed, displaying the maximum value and the minimum value. This code demonstrates a technique to determine the extreme values of a signed integer type through bitwise manipulation.

Output:

Maximum value: 2147483647
Minimum value:-2147483648

Conclusion

Understanding how negative values are represented in C++ is crucial for efficient and accurate numerical computations. The methods discussed here—sign-and-magnitude, two’s complement, one’s complement, and excess-k representation—provide different approaches to achieve this goal.

By mastering these representations, programmers can make informed decisions about the appropriate representation to use based on the requirements of their specific applications.

Related Article - C++ Number