mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
626 lines
20 KiB
626 lines
20 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 |
|
Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#include <sstream> |
|
#include <Corrade/TestSuite/Tester.h> |
|
|
|
#include "Magnum/Math/Half.h" |
|
#include "Magnum/Math/Vector3.h" |
|
|
|
namespace Magnum { namespace Math { namespace Test { |
|
|
|
struct HalfTest: Corrade::TestSuite::Tester { |
|
explicit HalfTest(); |
|
|
|
void unpack(); |
|
void pack(); |
|
void repack(); |
|
|
|
void unpack1k(); |
|
void unpack1kNaive(); |
|
void unpack1kTable(); |
|
void pack1k(); |
|
void pack1kNaive(); |
|
void pack1kTable(); |
|
|
|
void constructDefault(); |
|
void constructValue(); |
|
void constructData(); |
|
void constructNoInit(); |
|
void constructCopy(); |
|
|
|
void compare(); |
|
void compareNaN(); |
|
|
|
void promotion(); |
|
void negation(); |
|
|
|
void literal(); |
|
void debug(); |
|
|
|
private: |
|
/* Naive / ground-truth packing helpers */ |
|
UnsignedShort packNaive(Float value); |
|
Float unpackNaive(UnsignedShort value); |
|
|
|
/* Table-based packing helpers */ |
|
UnsignedInt convertMantissa(UnsignedInt i); |
|
UnsignedShort packTable(Float value); |
|
Float unpackTable(UnsignedShort value); |
|
|
|
UnsignedInt _mantissaTable[2048]; |
|
UnsignedInt _exponentTable[64]; |
|
UnsignedShort _offsetTable[64]; |
|
UnsignedShort _baseTable[512]; |
|
UnsignedByte _shiftTable[512]; |
|
}; |
|
|
|
typedef Math::Constants<Float> Constants; |
|
|
|
HalfTest::HalfTest() { |
|
addTests({&HalfTest::unpack, |
|
&HalfTest::pack}); |
|
|
|
addRepeatedTests({&HalfTest::repack}, 65536); |
|
|
|
addBenchmarks({ |
|
&HalfTest::unpack1k, |
|
&HalfTest::unpack1kNaive, |
|
&HalfTest::unpack1kTable, |
|
&HalfTest::pack1k, |
|
&HalfTest::pack1kNaive, |
|
&HalfTest::pack1kTable}, 100); |
|
|
|
addTests({&HalfTest::constructDefault, |
|
&HalfTest::constructValue, |
|
&HalfTest::constructData, |
|
&HalfTest::constructNoInit, |
|
&HalfTest::constructCopy, |
|
|
|
&HalfTest::compare}); |
|
|
|
addRepeatedTests({&HalfTest::compareNaN}, 65536); |
|
|
|
addTests({&HalfTest::promotion, |
|
&HalfTest::negation, |
|
|
|
&HalfTest::literal, |
|
&HalfTest::debug}); |
|
|
|
/* Calculate tables for table-based benchmark */ |
|
_mantissaTable[0] = 0; |
|
for(std::size_t i = 1; i != 1024; ++i) |
|
_mantissaTable[i] = convertMantissa(i); |
|
for(std::size_t i = 1024; i != 2048; ++i) |
|
_mantissaTable[i] = 0x38000000 + ((i - 1024) << 13); |
|
|
|
_exponentTable[0] = 0; |
|
for(std::size_t i = 1; i != 31; ++i) |
|
_exponentTable[i] = i << 23; |
|
_exponentTable[31] = 0x47800000; |
|
_exponentTable[32] = 0x80000000; |
|
for(std::size_t i = 33; i != 63; ++i) |
|
_exponentTable[i] = 0x80000000 + ((i - 32) << 23); |
|
_exponentTable[63] = 0xc7800000; |
|
|
|
for(std::size_t i = 0; i != 64; ++i) |
|
_offsetTable[i] = 1024; |
|
_offsetTable[0] = 0; |
|
_offsetTable[32] = 0; |
|
|
|
for(std::int_fast32_t i = 0; i != 256; ++i) { |
|
std::int_fast32_t e = i - 127; |
|
if(e < -24) { |
|
_baseTable[i | 0x000] = 0x0000; |
|
_baseTable[i | 0x100] = 0x8000; |
|
_shiftTable[i | 0x000] = 24; |
|
_shiftTable[i | 0x100] = 24; |
|
} else if(e < -14) { |
|
_baseTable[i | 0x000] = (0x0400 >> (-e - 14)); |
|
_baseTable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000; |
|
_shiftTable[i | 0x000] = -e - 1; |
|
_shiftTable[i | 0x100] = -e - 1; |
|
} else if(e <= 15) { |
|
_baseTable[i | 0x000] = ((e + 15) << 10); |
|
_baseTable[i | 0x100] = ((e + 15) << 10) | 0x8000; |
|
_shiftTable[i | 0x000] = 13; |
|
_shiftTable[i | 0x100] = 13; |
|
} else if(e < 128) { |
|
_baseTable[i | 0x000] = 0x7c00; |
|
_baseTable[i | 0x100] = 0xfc00; |
|
_shiftTable[i | 0x000] = 24; |
|
_shiftTable[i | 0x100] = 24; |
|
} else { |
|
_baseTable[i | 0x000] = 0x7c00; |
|
_baseTable[i | 0x100] = 0xfc00; |
|
_shiftTable[i | 0x000] = 13; |
|
_shiftTable[i | 0x100] = 13; |
|
} |
|
} |
|
} |
|
|
|
namespace { |
|
|
|
union FloatBits { |
|
UnsignedInt u; |
|
Float f; |
|
struct { |
|
UnsignedInt mantissa:23; |
|
UnsignedInt exponent:8; |
|
UnsignedInt sign:1; |
|
} bits; |
|
}; |
|
|
|
union HalfBits { |
|
UnsignedShort u; |
|
struct { |
|
UnsignedShort mantissa:10; |
|
UnsignedShort exponent:5; |
|
UnsignedShort sign:1; |
|
} bits; |
|
}; |
|
|
|
} |
|
|
|
/* float_to_half_full() from https://gist.github.com/rygorous/2156668, |
|
originally from ISPC */ |
|
UnsignedShort HalfTest::packNaive(Float value) { |
|
FloatBits f; |
|
f.f = value; |
|
HalfBits o{}; |
|
|
|
/* Signed zero/denormal (which will underflow) */ |
|
if(f.bits.exponent == 0) { |
|
o.bits.exponent = 0; |
|
|
|
/* Inf or NaN (all exponent bits set): NaN->qNaN and Inf->Inf */ |
|
} else if(f.bits.exponent == 255) { |
|
o.bits.exponent = 31; |
|
o.bits.mantissa = f.bits.mantissa ? 0x200 : 0; |
|
|
|
/* Normalized number */ |
|
} else { |
|
/* Exponent unbias the single, then bias the halfp */ |
|
Int newexp = f.bits.exponent - 127 + 15; |
|
|
|
/* Overflow, return signed infinity */ |
|
if(newexp >= 31) { |
|
o.bits.exponent = 31; |
|
|
|
/* Underflow */ |
|
} else if(newexp <= 0) { |
|
/* Mantissa might be non-zero */ |
|
if((14 - newexp) <= 24) { |
|
/* Hidden 1 bit */ |
|
UnsignedInt mant = f.bits.mantissa | 0x800000; |
|
o.bits.mantissa = mant >> (14 - newexp); |
|
|
|
/* Check for rounding */ |
|
if((mant >> (13 - newexp)) & 1) { |
|
/* Round, might overflow into exp bit, but this is OK */ |
|
o.u++; |
|
} |
|
} |
|
} else { |
|
o.bits.exponent = newexp; |
|
o.bits.mantissa = f.bits.mantissa >> 13; |
|
|
|
/* Check for rounding */ |
|
if(f.bits.mantissa & 0x1000) { |
|
/* Round, might overflow to inf, this is OK */ |
|
o.u++; |
|
} |
|
} |
|
} |
|
|
|
o.bits.sign = f.bits.sign; |
|
return o.u; |
|
} |
|
|
|
/* half_to_float_full() from https://gist.github.com/rygorous/2144712, |
|
originally from ISPC */ |
|
Float HalfTest::unpackNaive(UnsignedShort value) { |
|
HalfBits h{value}; |
|
FloatBits o{}; |
|
|
|
/* (Signed) zero */ |
|
if(h.bits.exponent == 0 && h.bits.mantissa == 0) { |
|
o.bits.sign = h.bits.sign; |
|
|
|
} else { |
|
/* Denormal (will convert to normalized) */ |
|
if(h.bits.exponent == 0) { |
|
/* Adjust mantissa so it's normalized (and keep track of exp |
|
adjust) */ |
|
Int e = -1; |
|
UnsignedInt m = h.bits.mantissa; |
|
do { |
|
e++; |
|
m <<= 1; |
|
} while((m & 0x400) == 0); |
|
|
|
o.bits.mantissa = (m & 0x3ff) << 13; |
|
o.bits.exponent = 127 - 15 - e; |
|
o.bits.sign = h.bits.sign; |
|
|
|
/* Inf/NaN */ |
|
} else if(h.bits.exponent == 0x1f) { |
|
/* Note: it's safe to treat both with the same code path by just |
|
truncating lower Mantissa bits in NaNs (this is valid). */ |
|
o.bits.mantissa = h.bits.mantissa << 13; |
|
o.bits.exponent = 255; |
|
o.bits.sign = h.bits.sign; |
|
|
|
/* Normalized number */ |
|
} else { |
|
o.bits.mantissa = h.bits.mantissa << 13; |
|
o.bits.exponent = 127 - 15 + h.bits.exponent; |
|
o.bits.sign = h.bits.sign; |
|
} |
|
} |
|
|
|
return o.f; |
|
} |
|
|
|
/* Jeroen van der Zijp -- Fast Half Float Conversions, 2008, |
|
ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf */ |
|
UnsignedInt HalfTest::convertMantissa(UnsignedInt i) { |
|
UnsignedInt m = i << 13; |
|
UnsignedInt e = 0; |
|
|
|
while(!(m & 0x00800000)) { |
|
e -= 0x00800000; |
|
m <<= 1; |
|
} |
|
|
|
m &= ~0x00800000; |
|
e += 0x38800000; |
|
return m | e; |
|
} |
|
|
|
UnsignedShort HalfTest::packTable(Float value) { |
|
const UnsignedInt v = reinterpret_cast<const UnsignedInt&>(value); |
|
return _baseTable[(v >> 23) & 0x1ff] + ((v & 0x007fffff) >> _shiftTable[(v >> 23) & 0x1ff]); |
|
} |
|
|
|
Float HalfTest::unpackTable(UnsignedShort value) { |
|
UnsignedInt result = _mantissaTable[_offsetTable[value >> 10] + (value & 0x3ff)] + _exponentTable[value >> 10]; |
|
return reinterpret_cast<Float&>(result); |
|
} |
|
|
|
void HalfTest::unpack() { |
|
CORRADE_COMPARE(Math::unpackHalf(0x0000), 0.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(0x3c00), 1.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(0x4000), 2.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(0x4200), 3.0f); |
|
|
|
CORRADE_COMPARE(unpackNaive(0x0000), 0.0f); |
|
CORRADE_COMPARE(unpackNaive(0x3c00), 1.0f); |
|
CORRADE_COMPARE(unpackNaive(0x4000), 2.0f); |
|
CORRADE_COMPARE(unpackNaive(0x4200), 3.0f); |
|
|
|
CORRADE_COMPARE(unpackTable(0x0000), 0.0f); |
|
CORRADE_COMPARE(unpackTable(0x3c00), 1.0f); |
|
CORRADE_COMPARE(unpackTable(0x4000), 2.0f); |
|
CORRADE_COMPARE(unpackTable(0x4200), 3.0f); |
|
|
|
/* Normals, denormals, specials */ |
|
CORRADE_COMPARE(Math::unpackHalf(0x8dc2), -0.000351f); |
|
CORRADE_COMPARE(Math::unpackHalf(0x57bc), 123.75f); |
|
CORRADE_COMPARE(Math::unpackHalf(0xfe00), -Constants::nan()); |
|
CORRADE_COMPARE(Math::unpackHalf(0x7e00), +Constants::nan()); |
|
CORRADE_COMPARE(Math::unpackHalf(0xfc00), -Constants::inf()); |
|
CORRADE_COMPARE(Math::unpackHalf(0x7c00), +Constants::inf()); |
|
|
|
CORRADE_COMPARE(unpackNaive(0x8dc2), -0.000351f); |
|
CORRADE_COMPARE(unpackNaive(0x57bc), 123.75f); |
|
CORRADE_COMPARE(unpackNaive(0xfe00), -Constants::nan()); |
|
CORRADE_COMPARE(unpackNaive(0x7e00), +Constants::nan()); |
|
CORRADE_COMPARE(unpackNaive(0xfc00), -Constants::inf()); |
|
CORRADE_COMPARE(unpackNaive(0x7c00), +Constants::inf()); |
|
|
|
CORRADE_COMPARE(unpackTable(0x8dc2), -0.000351f); |
|
CORRADE_COMPARE(unpackTable(0x57bc), 123.75f); |
|
CORRADE_COMPARE(unpackTable(0xfe00), -Constants::nan()); |
|
CORRADE_COMPARE(unpackTable(0x7e00), +Constants::nan()); |
|
CORRADE_COMPARE(unpackTable(0xfc00), -Constants::inf()); |
|
CORRADE_COMPARE(unpackTable(0x7c00), +Constants::inf()); |
|
|
|
/* Vector */ |
|
CORRADE_COMPARE(Math::unpackHalf(Math::Vector3<UnsignedShort>{0x0000, 0x4200, 0x3c00}), |
|
(Math::Vector3<Float>{0.0f, 3.0f, 1.0f})); |
|
} |
|
|
|
void HalfTest::pack() { |
|
CORRADE_COMPARE(Math::packHalf(0.0f), 0x0000); |
|
CORRADE_COMPARE(Math::packHalf(1.0f), 0x3c00); |
|
CORRADE_COMPARE(Math::packHalf(2.0f), 0x4000); |
|
CORRADE_COMPARE(Math::packHalf(3.0f), 0x4200); |
|
|
|
CORRADE_COMPARE(packNaive(0.0f), 0x0000); |
|
CORRADE_COMPARE(packNaive(1.0f), 0x3c00); |
|
CORRADE_COMPARE(packNaive(2.0f), 0x4000); |
|
CORRADE_COMPARE(packNaive(3.0f), 0x4200); |
|
|
|
CORRADE_COMPARE(packTable(0.0f), 0x0000); |
|
CORRADE_COMPARE(packTable(1.0f), 0x3c00); |
|
CORRADE_COMPARE(packTable(2.0f), 0x4000); |
|
CORRADE_COMPARE(packTable(3.0f), 0x4200); |
|
|
|
/* Rounding */ |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(-1024.01f)), -1024.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(-1024.50f)), -1025.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(-1024.99f)), -1025.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(+1024.01f)), +1024.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(+1024.50f)), +1025.0f); |
|
CORRADE_COMPARE(Math::unpackHalf(Math::packHalf(+1024.99f)), +1025.0f); |
|
|
|
/* Don't care about rounding behavior of the others */ |
|
|
|
/* Normals, denormals, specials */ |
|
CORRADE_COMPARE(Math::packHalf(-0.000351512f), 0x8dc2); |
|
CORRADE_COMPARE(Math::packHalf(123.7567f), 0x57bc); |
|
/* Emscripten doesn't differentiate NaNs and treats their sign slightly |
|
differently on different optimization levels. On MSVC they are somehow |
|
flipped around, so I'm testing w/o the sign. */ |
|
CORRADE_COMPARE(Math::packHalf(-Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(Math::packHalf(+Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(Math::packHalf(-Constants::inf()), 0xfc00); |
|
CORRADE_COMPARE(Math::packHalf(+Constants::inf()), 0x7c00); |
|
|
|
CORRADE_COMPARE(packNaive(-0.000351512f), 0x8dc2); |
|
CORRADE_COMPARE(packNaive(123.7567f), 0x57bc); |
|
/* Emscripten doesn't differentiate NaNs and treats their sign slightly |
|
differently on different optimization levels. On MSVC they are somehow |
|
flipped around, so I'm testing w/o the sign. */ |
|
CORRADE_COMPARE(packNaive(-Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(packNaive(+Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(packNaive(-Constants::inf()), 0xfc00); |
|
CORRADE_COMPARE(packNaive(+Constants::inf()), 0x7c00); |
|
|
|
CORRADE_COMPARE(packTable(-0.000351512f), 0x8dc2); |
|
CORRADE_COMPARE(packTable(123.7567f), 0x57bc); |
|
/* Emscripten doesn't differentiate NaNs and treats their sign slightly |
|
differently on different optimization levels. On MSVC they are somehow |
|
flipped around, so I'm testing w/o the sign. */ |
|
CORRADE_COMPARE(packTable(-Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(packTable(+Constants::nan()) & ~0x8000, 0x7e00); |
|
CORRADE_COMPARE(packTable(-Constants::inf()), 0xfc00); |
|
CORRADE_COMPARE(packTable(+Constants::inf()), 0x7c00); |
|
|
|
/* Vector */ |
|
CORRADE_COMPARE(Math::packHalf(Math::Vector3<Float>{0.0f, 3.0f, 1.0f}), |
|
(Math::Vector3<UnsignedShort>{0x0000, 0x4200, 0x3c00})); |
|
} |
|
|
|
void HalfTest::repack() { |
|
UnsignedShort in = testCaseRepeatId(); |
|
Float result = Math::unpackHalf(in); |
|
Float resultNaive = unpackNaive(in); |
|
Float resultTable = unpackTable(in); |
|
|
|
/* NaNs don't rountrip, but that's okay */ |
|
if(result != result) { |
|
CORRADE_VERIFY(result != result); |
|
CORRADE_VERIFY(resultNaive != resultNaive); |
|
CORRADE_VERIFY(resultTable != resultTable); |
|
|
|
/* Otherwise verify that both algos give the same results */ |
|
} else { |
|
CORRADE_COMPARE(result, resultTable); |
|
CORRADE_COMPARE(result, resultNaive); |
|
|
|
CORRADE_COMPARE(Math::packHalf(result), in); |
|
CORRADE_COMPARE(packTable(result), in); |
|
CORRADE_COMPARE(packNaive(result), in); |
|
} |
|
} |
|
|
|
void HalfTest::pack1k() { |
|
UnsignedInt out = 0; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += Math::packHalf(Float(i)*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::pack1kNaive() { |
|
UnsignedInt out = 0; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += packNaive(Float(i)*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::pack1kTable() { |
|
UnsignedInt out = 0; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += packTable(Float(i)*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::unpack1k() { |
|
Float out = 0.0f; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += Math::unpackHalf(i*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::unpack1kNaive() { |
|
Float out = 0.0f; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += unpackNaive(i*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::unpack1kTable() { |
|
Float out = 0.0f; |
|
CORRADE_BENCHMARK(100) |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
out += unpackTable(i*65); |
|
|
|
/* To avoid optimizing things out */ |
|
CORRADE_VERIFY(out); |
|
} |
|
|
|
void HalfTest::constructDefault() { |
|
constexpr Half a; |
|
CORRADE_COMPARE(Float(a), 0.0f); |
|
CORRADE_COMPARE(UnsignedShort(a), 0); |
|
CORRADE_COMPARE(a.data(), 0); |
|
|
|
constexpr Half b{ZeroInit}; |
|
CORRADE_COMPARE(Float(b), 0.0f); |
|
CORRADE_COMPARE(UnsignedShort(b), 0); |
|
CORRADE_COMPARE(b.data(), 0); |
|
|
|
CORRADE_VERIFY((std::is_nothrow_default_constructible<Half>::value)); |
|
CORRADE_VERIFY((std::is_nothrow_constructible<Half, ZeroInitT>::value)); |
|
} |
|
|
|
void HalfTest::constructValue() { |
|
Half a{3.5f}; |
|
CORRADE_COMPARE(Float(a), 3.5f); |
|
CORRADE_COMPARE(UnsignedShort(a), 0x4300); |
|
CORRADE_COMPARE(a.data(), 0x4300); |
|
|
|
CORRADE_VERIFY((std::is_nothrow_constructible<Half, Float>::value)); |
|
|
|
/* Implicit conversion is not allowed */ |
|
CORRADE_VERIFY(!(std::is_convertible<Float, Half>::value)); |
|
} |
|
|
|
void HalfTest::constructData() { |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
CORRADE_COMPARE(Float(a), 3.5f); |
|
CORRADE_COMPARE(UnsignedShort(a), 0x4300); |
|
|
|
CORRADE_VERIFY((std::is_nothrow_constructible<Half, UnsignedShort>::value)); |
|
|
|
/* Implicit conversion is not allowed */ |
|
CORRADE_VERIFY(!(std::is_convertible<UnsignedShort, Half>::value)); |
|
} |
|
|
|
void HalfTest::constructNoInit() { |
|
Half a{3.5f}; |
|
new(&a) Half{NoInit}; |
|
{ |
|
#if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ |
|
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); |
|
#endif |
|
CORRADE_COMPARE(a, Half{3.5f}); |
|
} |
|
|
|
CORRADE_VERIFY((std::is_nothrow_constructible<Half, NoInitT>::value)); |
|
|
|
/* Implicit construction is not allowed */ |
|
CORRADE_VERIFY(!(std::is_convertible<NoInitT, Half>::value)); |
|
} |
|
|
|
void HalfTest::constructCopy() { |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
constexpr Half b{a}; |
|
|
|
CORRADE_COMPARE(b, Half{3.5f}); |
|
|
|
CORRADE_VERIFY(std::is_nothrow_copy_constructible<Half>::value); |
|
CORRADE_VERIFY(std::is_nothrow_copy_assignable<Half>::value); |
|
} |
|
|
|
void HalfTest::compare() { |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
constexpr Half b{UnsignedShort(0x4301)}; |
|
|
|
CORRADE_VERIFY(a == a); |
|
CORRADE_VERIFY(a != b); |
|
} |
|
|
|
void HalfTest::compareNaN() { |
|
Half a{UnsignedShort(testCaseRepeatId())}; |
|
Float fa(a); |
|
|
|
/* If the values are NaNs as Float, they should also not compare as Half. |
|
Interestingly enough, writing Float(a) != Float(a) in expected confused |
|
the optimizer in Emscripten on higher optimization levels and it was |
|
always saying `true` for values >= 32769 (which is *not* right). */ |
|
CORRADE_COMPARE(a != a, fa != fa); |
|
} |
|
|
|
void HalfTest::promotion() { |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
constexpr Half b = +a; |
|
|
|
CORRADE_COMPARE(b, a); |
|
} |
|
|
|
void HalfTest::negation() { |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
constexpr Half b = -a; |
|
|
|
CORRADE_COMPARE(b, Half{-3.5f}); |
|
CORRADE_COMPARE(-b, a); |
|
} |
|
|
|
void HalfTest::literal() { |
|
using namespace Literals; |
|
|
|
Half a = 3.5_h; |
|
CORRADE_COMPARE(a, Half{UnsignedShort(0x4300)}); |
|
CORRADE_COMPARE(a, Half{3.5f}); |
|
} |
|
|
|
void HalfTest::debug() { |
|
using namespace Literals; |
|
|
|
std::ostringstream out; |
|
|
|
Debug{&out} << -3.64_h << Half{Constants::inf()} |
|
<< Math::Vector3<Half>{3.14159_h, -1.4142_h, 1.618_h}; |
|
#ifdef _MSC_VER |
|
CORRADE_COMPARE(out.str(), "-3.64063 inf Vector(3.14063, -1.41406, 1.61816)\n"); |
|
#elif defined(CORRADE_TARGET_ANDROID) |
|
CORRADE_COMPARE(out.str(), "-3.64062 Inf Vector(3.14062, -1.41406, 1.61816)\n"); |
|
#else |
|
CORRADE_COMPARE(out.str(), "-3.64062 inf Vector(3.14062, -1.41406, 1.61816)\n"); |
|
#endif |
|
} |
|
|
|
}}} |
|
|
|
CORRADE_TEST_MAIN(Magnum::Math::Test::HalfTest) |
|
|
|
|