70 lines
2.4 KiB
C++
70 lines
2.4 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <poly/math.h>
|
|
|
|
namespace poly {
|
|
|
|
// TODO(benvanik): replace with alternate implementation.
|
|
// XMConvertFloatToHalf
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
uint16_t float_to_half(float value) {
|
|
uint32_t Result;
|
|
uint32_t IValue = ((uint32_t *)(&value))[0];
|
|
uint32_t Sign = (IValue & 0x80000000U) >> 16U;
|
|
IValue = IValue & 0x7FFFFFFFU; // Hack off the sign
|
|
if (IValue > 0x47FFEFFFU) {
|
|
// The number is too large to be represented as a half. Saturate to
|
|
// infinity.
|
|
Result = 0x7FFFU;
|
|
} else {
|
|
if (IValue < 0x38800000U) {
|
|
// The number is too small to be represented as a normalized half.
|
|
// Convert it to a denormalized value.
|
|
uint32_t Shift = 113U - (IValue >> 23U);
|
|
IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift;
|
|
} else {
|
|
// Rebias the exponent to represent the value as a normalized half.
|
|
IValue += 0xC8000000U;
|
|
}
|
|
Result = ((IValue + 0x0FFFU + ((IValue >> 13U) & 1U)) >> 13U) & 0x7FFFU;
|
|
}
|
|
return (uint16_t)(Result | Sign);
|
|
}
|
|
|
|
// TODO(benvanik): replace with alternate implementation.
|
|
// XMConvertHalfToFloat
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
float half_to_float(uint16_t value) {
|
|
uint32_t Mantissa = (uint32_t)(value & 0x03FF);
|
|
uint32_t Exponent;
|
|
if ((value & 0x7C00) != 0) {
|
|
// The value is normalized
|
|
Exponent = (uint32_t)((value >> 10) & 0x1F);
|
|
} else if (Mantissa != 0) {
|
|
// The value is denormalized
|
|
// Normalize the value in the resulting float
|
|
Exponent = 1;
|
|
do {
|
|
Exponent--;
|
|
Mantissa <<= 1;
|
|
} while ((Mantissa & 0x0400) == 0);
|
|
Mantissa &= 0x03FF;
|
|
} else {
|
|
// The value is zero
|
|
Exponent = (uint32_t)-112;
|
|
}
|
|
uint32_t Result = ((value & 0x8000) << 16) | // Sign
|
|
((Exponent + 112) << 23) | // Exponent
|
|
(Mantissa << 13); // Mantissa
|
|
return *(float *)&Result;
|
|
}
|
|
|
|
} // namespace poly
|