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.
651 lines
21 KiB
651 lines
21 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
|
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 <cstring> |
|
#include <algorithm> |
|
#include <sstream> |
|
#include <Corrade/Containers/StridedArrayView.h> |
|
#include <Corrade/TestSuite/Tester.h> |
|
#include <Corrade/Utility/DebugStl.h> |
|
#if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) |
|
#include <Corrade/Utility/Tweakable.h> |
|
#endif |
|
|
|
#include "Magnum/Math/Half.h" |
|
#include "Magnum/Math/Packing.h" |
|
#include "Magnum/Math/Vector3.h" |
|
#include "Magnum/Math/StrictWeakOrdering.h" |
|
#include "Magnum/Math/PackingBatch.h" |
|
|
|
namespace Magnum { namespace Math { namespace Test { namespace { |
|
|
|
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 strictWeakOrdering(); |
|
|
|
void literal(); |
|
void debug(); |
|
#if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) |
|
void tweakable(); |
|
void tweakableError(); |
|
#endif |
|
}; |
|
|
|
typedef Math::Constants<Float> Constants; |
|
|
|
using namespace Literals; |
|
|
|
#if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) |
|
const struct { |
|
const char* name; |
|
const char* data; |
|
Half result; |
|
} TweakableData[] { |
|
{"fixed", "35.0_h", 35.0_h}, |
|
{"no zero before", ".5_h", 0.5_h}, |
|
{"no zero after", "35._h", 35.0_h}, |
|
{"exponential positive", "3.5e+1_h", 3.5e+1_h}, |
|
{"exponential negative", "350.0e-1_h", 350.0e-1_h}, |
|
{"positive", "+35.0_h", +35.0_h}, |
|
{"negative", "-35.0_h", -35.0_h} |
|
}; |
|
|
|
constexpr struct { |
|
const char* name; |
|
const char* data; |
|
Corrade::Utility::TweakableState state; |
|
const char* error; |
|
} TweakableErrorData[] { |
|
{"empty", "", Corrade::Utility::TweakableState::Recompile, |
|
"Utility::TweakableParser: is not a half literal\n"}, |
|
{"integral", "42_h", Corrade::Utility::TweakableState::Recompile, |
|
"Utility::TweakableParser: 42_h is not a half literal\n"}, |
|
{"garbage after", "42.b_h", Corrade::Utility::TweakableState::Recompile, |
|
"Utility::TweakableParser: unexpected characters b_h after a half literal\n"}, |
|
{"different suffix", "42.0u", Corrade::Utility::TweakableState::Recompile, /* not for double */ |
|
"Utility::TweakableParser: 42.0u has an unexpected suffix, expected _h\n"} |
|
}; |
|
#endif |
|
|
|
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::strictWeakOrdering, |
|
|
|
&HalfTest::literal, |
|
&HalfTest::debug}); |
|
|
|
#if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) |
|
addInstancedTests({&HalfTest::tweakable}, |
|
Corrade::Containers::arraySize(TweakableData)); |
|
|
|
addInstancedTests({&HalfTest::tweakableError}, |
|
Corrade::Containers::arraySize(TweakableErrorData)); |
|
#endif |
|
} |
|
|
|
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 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 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; |
|
} |
|
|
|
UnsignedShort packTable(const Float value) { |
|
UnsignedShort out; |
|
packHalfInto( |
|
Corrade::Containers::StridedArrayView2D<const Float>{{&value, 1}, {1, 1}}, |
|
Corrade::Containers::StridedArrayView2D<UnsignedShort>{{&out, 1}, {1, 1}}); |
|
return out; |
|
} |
|
|
|
Float unpackTable(const UnsignedShort value) { |
|
Float out; |
|
unpackHalfInto( |
|
Corrade::Containers::StridedArrayView2D<const UnsignedShort>{{&value, 1}, {1, 1}}, |
|
Corrade::Containers::StridedArrayView2D<Float>{{&out, 1}, {1, 1}}); |
|
return out; |
|
} |
|
|
|
void HalfTest::unpack() { |
|
CORRADE_COMPARE(Math::unpackHalf(0x0000), 0.0f); |
|
|
|
/* 0b0011110000000000 */ |
|
CORRADE_COMPARE(Math::unpackHalf(0x3c00), 1.0f); |
|
|
|
/* 0b0100000000000000 */ |
|
CORRADE_COMPARE(Math::unpackHalf(0x4000), 2.0f); |
|
|
|
/* 0b0100001000000000 */ |
|
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); |
|
|
|
/* 0b0011110000000000 */ |
|
CORRADE_COMPARE(Math::packHalf(1.0f), 0x3c00); |
|
|
|
/* 0b0100000000000000 */ |
|
CORRADE_COMPARE(Math::packHalf(2.0f), 0x4000); |
|
|
|
/* 0b0100001000000000 */ |
|
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 all 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() { |
|
Float src[1000]; |
|
UnsignedShort dst[1000]; |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
src[i] = i*65; |
|
|
|
CORRADE_BENCHMARK(100) { |
|
packHalfInto(Corrade::Containers::StridedArrayView2D<Float>{src, {1, 1000}}, |
|
Corrade::Containers::StridedArrayView2D<UnsignedShort>{dst, {1, 1000}}); |
|
} |
|
} |
|
|
|
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() { |
|
UnsignedShort src[1000]; |
|
Float dst[1000]; |
|
for(std::uint_fast16_t i = 0; i != 1000; ++i) |
|
src[i] = i*65; |
|
|
|
CORRADE_BENCHMARK(100) { |
|
unpackHalfInto(Corrade::Containers::StridedArrayView2D<UnsignedShort>{src, {1, 1000}}, |
|
Corrade::Containers::StridedArrayView2D<Float>{dst, {1, 1000}}); |
|
} |
|
} |
|
|
|
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)); |
|
|
|
/* Implicit construction is not allowed */ |
|
CORRADE_VERIFY(!(std::is_convertible<ZeroInitT, Half>::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::strictWeakOrdering() { |
|
StrictWeakOrdering o; |
|
constexpr Half a{UnsignedShort(0x4300)}; |
|
constexpr Half b{UnsignedShort(0x5100)}; |
|
|
|
CORRADE_VERIFY( o(a, b)); |
|
CORRADE_VERIFY(!o(b, a)); |
|
CORRADE_VERIFY(!o(a, a)); |
|
} |
|
|
|
void HalfTest::literal() { |
|
Half a = 3.5_h; |
|
CORRADE_COMPARE(a, Half{UnsignedShort(0x4300)}); |
|
CORRADE_COMPARE(a, Half{3.5f}); |
|
} |
|
|
|
void HalfTest::debug() { |
|
std::ostringstream out; |
|
|
|
Debug{&out} << -36.41_h << Half{Constants::inf()} |
|
<< Math::Vector3<Half>{3.14159_h, -1.4142_h, 1.618_h}; |
|
#ifdef _MSC_VER |
|
CORRADE_COMPARE(out.str(), "-36.41 inf Vector(3.141, -1.414, 1.618)\n"); |
|
#else |
|
CORRADE_COMPARE(out.str(), "-36.41 inf Vector(3.141, -1.414, 1.618)\n"); |
|
#endif |
|
} |
|
|
|
#if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) |
|
void HalfTest::tweakable() { |
|
auto&& data = TweakableData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
Corrade::Utility::TweakableState state; |
|
Half result; |
|
std::tie(state, result) = Corrade::Utility::TweakableParser<Half>::parse({data.data, std::strlen(data.data)}); |
|
CORRADE_COMPARE(state, Corrade::Utility::TweakableState::Success); |
|
CORRADE_COMPARE(result, data.result); |
|
} |
|
|
|
void HalfTest::tweakableError() { |
|
auto&& data = TweakableErrorData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
std::ostringstream out; |
|
Warning redirectWarning{&out}; |
|
Error redirectError{&out}; |
|
Corrade::Utility::TweakableState state = Corrade::Utility::TweakableParser<Half>::parse({data.data, std::strlen(data.data)}).first; |
|
CORRADE_COMPARE(out.str(), data.error); |
|
CORRADE_COMPARE(state, data.state); |
|
} |
|
#endif |
|
|
|
}}}} |
|
|
|
CORRADE_TEST_MAIN(Magnum::Math::Test::HalfTest)
|
|
|