0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include "dm_services.h"
0026 #include "bw_fixed.h"
0027
0028
0029 #define MIN_I64 \
0030 (int64_t)(-(1LL << 63))
0031
0032 #define MAX_I64 \
0033 (int64_t)((1ULL << 63) - 1)
0034
0035 #define FRACTIONAL_PART_MASK \
0036 ((1ULL << BW_FIXED_BITS_PER_FRACTIONAL_PART) - 1)
0037
0038 #define GET_FRACTIONAL_PART(x) \
0039 (FRACTIONAL_PART_MASK & (x))
0040
0041 static uint64_t abs_i64(int64_t arg)
0042 {
0043 if (arg >= 0)
0044 return (uint64_t)(arg);
0045 else
0046 return (uint64_t)(-arg);
0047 }
0048
0049 struct bw_fixed bw_int_to_fixed_nonconst(int64_t value)
0050 {
0051 struct bw_fixed res;
0052 ASSERT(value < BW_FIXED_MAX_I32 && value > BW_FIXED_MIN_I32);
0053 res.value = value << BW_FIXED_BITS_PER_FRACTIONAL_PART;
0054 return res;
0055 }
0056
0057 struct bw_fixed bw_frc_to_fixed(int64_t numerator, int64_t denominator)
0058 {
0059 struct bw_fixed res;
0060 bool arg1_negative = numerator < 0;
0061 bool arg2_negative = denominator < 0;
0062 uint64_t arg1_value;
0063 uint64_t arg2_value;
0064 uint64_t remainder;
0065
0066
0067 uint64_t res_value;
0068
0069 ASSERT(denominator != 0);
0070
0071 arg1_value = abs_i64(numerator);
0072 arg2_value = abs_i64(denominator);
0073 res_value = div64_u64_rem(arg1_value, arg2_value, &remainder);
0074
0075 ASSERT(res_value <= BW_FIXED_MAX_I32);
0076
0077
0078 {
0079 uint32_t i = BW_FIXED_BITS_PER_FRACTIONAL_PART;
0080
0081 do
0082 {
0083 remainder <<= 1;
0084
0085 res_value <<= 1;
0086
0087 if (remainder >= arg2_value)
0088 {
0089 res_value |= 1;
0090 remainder -= arg2_value;
0091 }
0092 } while (--i != 0);
0093 }
0094
0095
0096 {
0097 uint64_t summand = (remainder << 1) >= arg2_value;
0098
0099 ASSERT(res_value <= MAX_I64 - summand);
0100
0101 res_value += summand;
0102 }
0103
0104 res.value = (int64_t)(res_value);
0105
0106 if (arg1_negative ^ arg2_negative)
0107 res.value = -res.value;
0108 return res;
0109 }
0110
0111 struct bw_fixed bw_floor2(
0112 const struct bw_fixed arg,
0113 const struct bw_fixed significance)
0114 {
0115 struct bw_fixed result;
0116 int64_t multiplicand;
0117
0118 multiplicand = div64_s64(arg.value, abs_i64(significance.value));
0119 result.value = abs_i64(significance.value) * multiplicand;
0120 ASSERT(abs_i64(result.value) <= abs_i64(arg.value));
0121 return result;
0122 }
0123
0124 struct bw_fixed bw_ceil2(
0125 const struct bw_fixed arg,
0126 const struct bw_fixed significance)
0127 {
0128 struct bw_fixed result;
0129 int64_t multiplicand;
0130
0131 multiplicand = div64_s64(arg.value, abs_i64(significance.value));
0132 result.value = abs_i64(significance.value) * multiplicand;
0133 if (abs_i64(result.value) < abs_i64(arg.value)) {
0134 if (arg.value < 0)
0135 result.value -= abs_i64(significance.value);
0136 else
0137 result.value += abs_i64(significance.value);
0138 }
0139 return result;
0140 }
0141
0142 struct bw_fixed bw_mul(const struct bw_fixed arg1, const struct bw_fixed arg2)
0143 {
0144 struct bw_fixed res;
0145
0146 bool arg1_negative = arg1.value < 0;
0147 bool arg2_negative = arg2.value < 0;
0148
0149 uint64_t arg1_value = abs_i64(arg1.value);
0150 uint64_t arg2_value = abs_i64(arg2.value);
0151
0152 uint64_t arg1_int = BW_FIXED_GET_INTEGER_PART(arg1_value);
0153 uint64_t arg2_int = BW_FIXED_GET_INTEGER_PART(arg2_value);
0154
0155 uint64_t arg1_fra = GET_FRACTIONAL_PART(arg1_value);
0156 uint64_t arg2_fra = GET_FRACTIONAL_PART(arg2_value);
0157
0158 uint64_t tmp;
0159
0160 res.value = arg1_int * arg2_int;
0161
0162 ASSERT(res.value <= BW_FIXED_MAX_I32);
0163
0164 res.value <<= BW_FIXED_BITS_PER_FRACTIONAL_PART;
0165
0166 tmp = arg1_int * arg2_fra;
0167
0168 ASSERT(tmp <= (uint64_t)(MAX_I64 - res.value));
0169
0170 res.value += tmp;
0171
0172 tmp = arg2_int * arg1_fra;
0173
0174 ASSERT(tmp <= (uint64_t)(MAX_I64 - res.value));
0175
0176 res.value += tmp;
0177
0178 tmp = arg1_fra * arg2_fra;
0179
0180 tmp = (tmp >> BW_FIXED_BITS_PER_FRACTIONAL_PART) +
0181 (tmp >= (uint64_t)(bw_frc_to_fixed(1, 2).value));
0182
0183 ASSERT(tmp <= (uint64_t)(MAX_I64 - res.value));
0184
0185 res.value += tmp;
0186
0187 if (arg1_negative ^ arg2_negative)
0188 res.value = -res.value;
0189 return res;
0190 }
0191