-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfixed16.c
More file actions
190 lines (157 loc) · 4.93 KB
/
fixed16.c
File metadata and controls
190 lines (157 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
Copyright 2011 Hoyoung Lee.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, please visit www.gnu.org.
*/
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <stdlib.h>
#include <inttypes.h>
#include "fixed16.h"
fixed16_t fixed16_convert(fixed16_t fix16, fixed16_qformat_t q1, fixed16_qformat_t q2)
{
int dist;
dist = q2 - q1;
if (dist > 0) fix16 <<= dist;
else if (dist < 0) fix16 >>= abs(dist);
/*
float temp = fixed16_to_float(fix16, q1);
fixed16_t fix16 = float_to_fixed16(temp, q2);
*/
return fix16;
}
fixed16_qformat_t fixed16_get_qformat_covering_range(double fmin, double fmax)
{
fixed16_qformat_t q;
int16_t fixmin = INT16_MIN, fixmax = INT16_MAX;
for (q = Q0_15; q >= Q14_1; --q) {
if ((fmin >= fixed16_to_double(fixmin, q)) &&
(fmax <= fixed16_to_double(fixmax, q)))
return q;
}
fprintf(stderr, "This range isn't covered by 'fixed16' at %s, line %d\n", __FILE__, __LINE__);
//exit(-1);
return q; // Q16_OUT_OF_RANGE
}
fixed16_qformat_t fixed16_get_qformat_covering_resolution(double epsilon)
{
fixed16_t value;
fixed16_qformat_t q;
value = 1;
for (q = Q14_1; q <= Q0_15; ++q) {
if (epsilon >= fixed16_to_double(value, q))
return q;
}
fprintf(stderr, "This resolution isn't specified by 'fixed16' at %s, line %d\n", __FILE__, __LINE__);
//exit(-1);
return q; // Q16_OUT_OF_RANGE
}
void fixed16_generate_resolutions_in_float(void)
{
fixed16_qformat_t q;
printf("Q format of 16bit - Unit resolution in float-typed container\n");
for (q = Q14_1; q <= Q0_15; ++q) {
printf("\tQ%d.%d:\t%.18e\n", 15-q, q, fixed16_to_float((fixed16_t)1, q));
}
}
void fixed16_generate_resolutions_in_double(void)
{
fixed16_qformat_t q;
printf("Q format of 16bit - Unit resolution in double-typed container\n");
for (q = Q14_1; q <= Q0_15; ++q) {
printf("\tQ%d.%d:\t%.18e\n", 15-q, q, fixed16_to_double((fixed16_t)1, q));
}
}
void fixed16_generate_ranges_in_float(void)
{
fixed16_t vmin, vmax;
fixed16_qformat_t q;
printf("Q format of 16bit - Covering range in float-typed container\n");
vmin = INT16_MIN;
vmax = INT16_MAX;
for (q = Q14_1; q <= Q0_15; ++q) {
printf("\tQ%d.%d:\t[%.18e, %.18e]\n", 15-q, q, fixed16_to_float(vmin, q), fixed16_to_float(vmax, q));
}
}
void fixed16_generate_ranges_in_double(void)
{
fixed16_t vmin, vmax;
fixed16_qformat_t q;
printf("Q format of 16bit - Covering range in double-typed container\n");
vmin = INT16_MIN;
vmax = INT16_MAX;
for (q = Q14_1; q <= Q0_15; q++) {
printf("\tQ%d.%d:\t[%.18e, %.18e]\n", 15-q, q, fixed16_to_double(vmin, q), fixed16_to_double(vmax, q));
}
}
fixed16_t fixed16_add_with_trim(fixed16_t a, fixed16_t b)
{
fixed16_t c;
int32_t tmp;
tmp = (int32_t)a + (int32_t)b;
if (tmp > INT16_MAX) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MAX;
} else if (tmp < INT16_MIN) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MIN;
}
c = (fixed16_t)tmp;
return c;
}
fixed16_t fixed16_subtract_with_trim(fixed16_t a, fixed16_t b)
{
fixed16_t c;
int32_t tmp;
tmp = (int32_t)a - (int32_t)b;
if (tmp > INT16_MAX) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MAX;
} else if (tmp < INT16_MIN) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MIN;
}
c = (fixed16_t)tmp;
return c;
}
fixed16_t fixed16_multiply(fixed16_t a, fixed16_t b, fixed16_qformat_t q)
{
fixed16_t c;
int32_t tmp;
tmp = (int32_t)a * (int32_t)b;
// Rounding
tmp += (1 << (q-1));
tmp >>= q;
if (tmp > INT16_MAX) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MAX;
} else if (tmp < INT16_MIN) {
fprintf(stderr, "The saturation is occurred at %s, line %d.\n", __FILE__, __LINE__);
tmp = INT16_MIN;
}
c = (fixed16_t)tmp;
return c;
}
fixed16_t fixed16_divide(fixed16_t a, fixed16_t b, fixed16_qformat_t q)
{
fixed16_t c;
int32_t tmp;
// pre-multiply by the base (Upscale to Q16 so that the result will be in Q8 format)
tmp = (int32_t)a << q;
// Rounding: mid values are rounded up (down for negative values).
if ((tmp >= 0 && b >= 0) || (tmp < 0 && b < 0))
tmp += b >> 1;
else
tmp -= b >> 1;
c = (fixed16_t)(tmp/b);
return c;
}