/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2024, Paul Elder * * Fixed / floating point conversions */ #pragma once #include #include namespace libcamera { namespace ipa { #ifndef __DOXYGEN__ template && std::is_floating_point_v> * = nullptr> #else template #endif constexpr R floatingToFixedPoint(T number) { static_assert(sizeof(int) >= sizeof(R)); static_assert(I + F <= sizeof(R) * 8); /* * The intermediate cast to int is needed on arm platforms to properly * cast negative values. See * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/ */ R mask = (1 << (F + I)) - 1; R frac = static_cast(static_cast(std::round(number * (1 << F)))) & mask; return frac; } #ifndef __DOXYGEN__ template && std::is_integral_v> * = nullptr> #else template #endif constexpr R fixedToFloatingPoint(T number) { static_assert(sizeof(int) >= sizeof(T)); static_assert(I + F <= sizeof(T) * 8); /* * Recreate the upper bits in case of a negative number by shifting the sign * bit from the fixed point to the first bit of the unsigned and then right shifting * by the same amount which keeps the sign bit in place. * This can be optimized by the compiler quite well. */ int remaining_bits = sizeof(int) * 8 - (I + F); int t = static_cast(static_cast(number) << remaining_bits) >> remaining_bits; return static_cast(t) / static_cast(1 << F); } } /* namespace ipa */ } /* namespace libcamera */