I started off with a simple function template for extracting the bit patterns of integral types
:
template <class Type> std::string as_binary_string( Type value ) { static_assert( std::is_integral<Type>::value, "Integral type required." ); return std::bitset<sizeof( Type ) * 8>( value ).to_string(); }
The above works without issue as is. I then ported this into a class template
with some other functionality of the integral type
: size in bytes, the max number of bit combinations, & the number of bits this type has. I save the bit pattern
into an std::string
. The class template
worked without issue.
Then I came up with another function for doing something similar with floating point types
thanks to user iBug
.
template <class T> std::string float_as_binary_string( T value ) { static_assert(std::is_floating_point<T>::value, "Floating Point type required."); std::bitset<sizeof( T ) * CHAR_BIT> b; std::uint8_t buf[sizeof( T ) * CHAR_BIT]; std::memcpy( buf, &value, sizeof( T ) ); for ( int i = 0; i < sizeof( T ); ++i ) { std::uint8_t cur = buf[i]; int offset = i * CHAR_BIT; for ( int bit = 0; bit < CHAR_BIT; ++bit ) { b[offset] = cur & 1; ++offset; // Move to next bit in b cur >>= 1; // Move to next bit in array } } return b.to_string(); }
I am in the process of porting this into the same class template
.
I have two options: I could partially specialize
this class template
or the more preferred member function overload
that you can see below in this class template
template<class ArithmeticType>
class BinaryRep {
public:
static_assert(std::is_arithmetic<ArithmeticType>::value, "Type must be an Arithmetic Type.");
static const std::size_t sizeInBytes_ = sizeof( ArithmeticType );
static const std::size_t standardByteWidth_ = 8;
static const std::size_t numbits_ = sizeInBytes_ * standardByteWidth_;
private:
typedef typename std::make_unsigned<ArithmeticType>::type unsigned_t;
const static unsigned_t maxVal_ = -1;
ArithmeticType arTy_;
std::string strBitPattern_;
//std::vector<unsigned char> bitPattern_ { 0 };
public:
BinaryRep() : arTy_(0) {
}
explicit BinaryRep( const ArithmeticType& arTy ) : arTy_( arTy ) {
processBits( arTy_ );
}
void setVal( const ArithmeticType& arTy ) {
arTy_ = arTy;
processBits( arTy_ );
}
const std::string& getBitPattern() const {
return strBitPattern_;
}
void clearBits() {
strBitPattern_.clear();
}
static void showMeta() {
std::ostringstream ostr;
ostr << "Max Value: " << +maxVal_ << " ";
ostr << "Size in bytes: " << sizeInBytes_ << " ";
ostr << "Number of bits: " << numbits_ << "\n";
std::cout << ostr.str();
}
static const std::string getMeta() {
std::ostringstream ostr;
ostr << "Max Value: " << +maxVal_ << " ";
ostr << "Size in bytes: " << sizeInBytes_ << " ";
ostr << "Number of bits: " << numbits_ << "\n";
return ostr.str();
}
friend std::ostream& operator<<( std::ostream& out, const BinaryRep& val ) {
std::ostringstream ostring;
ostring << "Val: " << +val.arTy_ << " ";
ostring << "Bit Pattern: ";
ostring << val.strBitPattern_ << std::endl;
out << ostring.str();
return out;
}
private:
template<class BasicType = ArtithmeticType>
void processBits( BasicType bt = arTy_ ) {
strBitPattern_ = std::bitset<sizeof( BasicType ) * 8>( bt ).to_string();
}
// float
template<>
void processBits<float>( float value ) {
std::bitset<sizeof( ArithmeticType ) * CHAR_BIT> b;
std::uint8_t buf[sizeof( ArithmeticType ) * CHAR_BIT];
std::memcpy( buf, &value, sizeof( ArithmeticType ) );
for ( int i = 0; i < sizeof( ArithmeticType ); ++i ) {
std::uint8_t cur = buf[i];
int offset = i * CHAR_BIT;
for ( int bit = 0; bit < CHAR_BIT; ++bit ) {
b[offset] = cur & 1;
++offset; // Move to next bit in b
cur >>= 1; // Move to next bit in array
}
}
strBitPattern_ = b.to_string();
}
// double
template<>
void processBits<double>( double value ) {
std::bitset<sizeof( ArithmeticType ) * CHAR_BIT> b;
std::uint8_t buf[sizeof( ArithmeticType ) * CHAR_BIT];
std::memcpy( buf, &value, sizeof( ArithmeticType ) );
for ( int i = 0; i < sizeof( ArithmeticType ); ++i ) {
std::uint8_t cur = buf[i];
int offset = i * CHAR_BIT;
for ( int bit = 0; bit < CHAR_BIT; ++bit ) {
b[offset] = cur & 1;
++offset; // Move to next bit in b
cur >>= 1; // Move to next bit in array
}
}
strBitPattern_ = b.to_string();
}
};
However, there are 2 main issues:
-
1st issue: The above will compile, build and run if used as such:
int main() { BinaryRep<char> brc; brc.setVal( 5 ); std::cout << brc << std::endl; return 0; }
However if I try to use it this way:
int main() { BinaryRep<float> brf; brf.setVal( 1.0f ); std::cout << brf << std::endl; return 0; }
This will not compile and gives this MS Visual Studio 2017 CE error and I do know why!
1>------ Build started: Project: PracticeMath, Configuration: Debug Win32 ------ 1>PracticeMath.cpp 1>c:\program files (x86)\microsoft visual studio\2017 community\vc\tools\msvc\14.11.25503\include\type_traits(1008): error C2338: make_signed<T>/make_unsigned<T> require that T shall be a (possibly cv-qualified) integral type or enumeration but not a bool type. 1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.11.25503\include\type_traits(1072): note: see reference to class template instantiation 'std::_Change_sign<_Ty>' being compiled 1> with 1> [ 1> _Ty=float 1> ] 1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\binaryrep.h(42): note: see reference to class template instantiation 'std::make_unsigned<ArithmeticType>' being compiled 1> with 1> [ 1> ArithmeticType=float 1> ] 1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(77): note: see reference to class template instantiation 'BinaryRep<float>' being compiled 1>Done building project "PracticeMath.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
When trying to instantiate this
class template
as either afloat
ordouble
type
, it is failing for these lines of code from within theclass template
.typedef typename std::make_unsigned<ArithmeticType>::type unsigned_t; const static unsigned_t maxVal_ = -1;
It can not make the deduced type of
float
nordouble
to be made as unsigned.I need a work around for this issue; and it is starting to make me think I might need to
partial specialize
this instead of using preferredfunction overload
.
-
2nd issue: If I'm not
partially specializing
and able to stick with themember function overload
: within theshowMeta()
andgetMeta()
functions I do need to report the correct values.static void showMeta() { std::ostringstream ostr; ostr << "Max Value: " << +maxVal_ << " "; ostr << "Size in bytes: " << sizeInBytes_ << " "; ostr << "Number of bits: " << numbits_ << "\n"; std::cout << ostr.str(); } static const std::string getMeta() { std::ostringstream ostr; ostr << "Max Value: " << +maxVal_ << " "; ostr << "Size in bytes: " << sizeInBytes_ << " "; ostr << "Number of bits: " << numbits_ << "\n"; return ostr.str(); }
Here
SizeInBytes_
&numBits_
are self explanatory. The membermaxVal
does not mean the max numerical value that the variable can represent, in this context it means the max number of binary bit combinational representations thevariable type
can support. For a simple example achar
& andunsigned char
that is1 byte
or8 bits
in size can support256
uniquely differentbinary bit representations...
At this point I'm not sure if I should stick with trying to overload
the member functions, or if I do need to partially specialize
this class template
and once I resolve that, its a matter of getting the right meta
values for floating point types
. I don't know how to resolve the issue with std::make_unsigned<Type>
for floating_point
types
. The final piece of information that is also viably important is how would you also calculate the maximum number of combinatorial binary representations
for floating point types
: float
& double
. For floating point types the most common types supported are by the IEEE standard
as they are the preferred floating point types. At this current stage the endian
is not an issue.
Aucun commentaire:
Enregistrer un commentaire