I have created a simple function to add two integral numbers represented with std::bitset<8>
. Inside the method I have a result bitset that stores the result of the operation. When calling the std::bitset<N>::test
method on the result
object that is returned from the function it does not work as expect. It either returns false
every time or it does not work entirely as when I am using debugger watch list I get class "std::bitset<8>" has no member "test"
.
The following code does not work as expected. I cannot call method test
on the object r
. Although there is no compile time nor runtime error. The result is wrong though as if r.test always returned false.
std::bitset<8> add(const std::bitset<8>& a, const std::bitset<8>& b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
r[i] = a.test(i) ^ b.test(i) ^ r.test(i);
if (i < a.size() - 1)
{
r[i + 1] = (a.test(i) && b.test(i)) || (r.test(i) && a.test(i)) || (r.test(i) && b.test(i));
}
}
return r;
}
When I make a copy of the result bitset in each loop step it does work as expected. I can call the method test
on the object copy
.
std::bitset<8> add(const std::bitset<8>& a, const std::bitset<8>& b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
const auto copy = r;
r[i] = a.test(i) ^ b.test(i) ^ copy.test(i);
if (i < a.size() - 1)
{
r[i + 1] = (a.test(i) && b.test(i)) || (copy.test(i) && a.test(i)) || (copy.test(i) && b.test(i));
}
}
return r;
}
The code was written on Windows with latest version of Visual Studio Community edition, language standard set to Preview - Features from the Latest C++ Working Draft (/std:c++latest)
and built ISO C++23 Standard Library modules.
Here is full snippet of the code that does not work as expected, or at least it does not work as I expected it to work:
#include <bit>
#include <bitset>
#include <iostream>
std::bitset<8> to_bitset(std::int8_t value)
{
return { static_cast<std::uint8_t>(value) };
}
std::int8_t to_int(const std::bitset<8>& bitset)
{
return (std::int8_t)bitset.to_ulong();
}
std::bitset<8> add_bad_result(const std::bitset<8>& a, const std::bitset<8>& b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
r[i] = a.test(i) ^ b.test(i) ^ r.test(i);
if (i < a.size() - 1)
{
r[i + 1] = (a.test(i) && b.test(i)) || (r.test(i) && a.test(i)) || (r.test(i) && b.test(i));
}
}
return r;
}
std::bitset<8> add_good_result(const std::bitset<8>& a, const std::bitset<8>& b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
const auto copy = r;
r[i] = a.test(i) ^ b.test(i) ^ copy.test(i);
if (i < a.size() - 1)
{
r[i + 1] = (a.test(i) && b.test(i)) || (copy.test(i) && a.test(i)) || (copy.test(i) && b.test(i));
}
}
return r;
}
int main()
{
auto a = 7;
auto b = 1;
// bad result
std::cout << add_bad_result(to_bitset(a), to_bitset(b)) << std::endl;
// output: 00001100
// good result
std::cout << add_good_result(to_bitset(a), to_bitset(b)) << std::endl;
// output: 00001000
return 0;
}
The bitset
works fine. Your logic in the "bad" function doesn't work because the r[i + 1]
assignment tests bit r[i]
which has already been set to the new value but the check needs to be done with the original boolean value for r[i]
. You have to write your logic so that either all assignments happen after all tests or all tested values are retrieved first.
std::bitset<8> add_1(std::bitset<8> a, std::bitset<8> b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
bool add = a[i] ^ b[i] ^ r[i];
bool carry_out = (a[i] && b[i]) || (r[i] && a[i]) || (r[i] && b[i]);
r[i] = add;
if(i + 1 < a.size())
r[i + 1] = carry_out;
}
return r;
}
std::bitset<8> add_2(std::bitset<8> a, std::bitset<8> b)
{
std::bitset<8> r;
for (size_t i = 0; i < a.size(); i++)
{
bool carry_in = r[i];
r[i] = a[i] ^ b[i] ^ carry_in;
if(i + 1 < a.size())
r[i + 1] = (a[i] && b[i]) || (carry_in && a[i]) || (carry_in && b[i]);
}
return r;
}
Side-notes:
carry_out = (a[i] && b[i]) || (carry_in && (a[i] ^ b[i]))
bitset<8>
as a const reference. Copy will be faster for bitsets up to 64, probably 128 values