├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── README.org ├── fixnum_string.c ├── fpc.c ├── fpc.h ├── main.c ├── test_output.txt └── tests.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /fpc 2 | *~ 3 | /convert.c 4 | /convert 5 | *.o 6 | /.tramp_history 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -Wall -g 2 | LIBS := -lm 3 | SRC := fpc.c main.c 4 | OBJS := $(patsubst %.c, %.o, $(SRC)) 5 | CONVERT_LIBS := -lm 6 | CONVERT_SRC := convert.c 7 | CONVERT_OBJS := $(patsubst %.c, %.o, $(CONVERT_SRC)) 8 | 9 | .PHONY: all 10 | all: test 11 | 12 | fpc: $(OBJS) 13 | $(CC) $(CFLAGS) $(OBJS) $(LIBS) -o $@ 14 | 15 | convert: $(CONVERT_OBJS) 16 | $(CC) $(CONVERT_OBJS) $(LIBS) -o $@ 17 | 18 | %.o: %.c 19 | $(CC) -c $(CFLAGS) $*.c 20 | 21 | .PHONY: test_output 22 | test_output: 23 | ./tests.sh &> test_output.txt 24 | 25 | .PHONY: test 26 | test: fpc 27 | ./tests.sh 2>&1 | diff -U 3 test_output.txt - 28 | 29 | .PHONY: clean 30 | clean: 31 | rm -f fpc 32 | rm -f $(OBJS) 33 | rm -f convert 34 | rm -f $(CONVERT_SRC) 35 | rm -f $(CONVERT_OBJS) 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fixed-point Calculator 2 | 3 | This program takes a range [min, max] and precision and calculates constants and information to be used in code performing calculations in this range using fixed-point integer math. 4 | 5 | This is not an official Google product. 6 | 7 | # Try it! 8 | 9 | $ git clone ssh://git@stash.nestlabs.com:7999/user/fpc.git 10 | $ make 11 | $ ./fpc -g 30 1800 0.1 12 | [PARAMETERS] 13 | min: 30 (30 requested) 14 | max: 1800 (1800 requested) 15 | precision: 0.0625 (0.1 requested) 16 | 17 | [CODE] 18 | code density: 62.5% 19 | offset: 0 20 | code range: [480, 28800] 21 | 22 | [ENCODING] 23 | machine bit width: 16 (15 used) 24 | fractional bits: 4 25 | integer bits: 11 26 | use signed: no 27 | machine integer type: uint16_t 28 | Q notation: Qu12.4 29 | 30 | [CONVERSION] 31 | #include 32 | #include 33 | // can lose precision, for display only 34 | double convert_to_double(uint16_t x) { 35 | if(x < UINT16_C(480) && 36 | x > UINT16_C(28800)) { 37 | return NAN; 38 | } 39 | return round(ldexp(x, -4) * 10) * 0.1; 40 | } 41 | $ make convert 42 | $ ./convert 480 600 10000 28800 43 | 480 -> 30 44 | 600 -> 37.5 45 | 10000 -> 625 46 | 28800 -> 1800 47 | 48 | # Also, check this out: 49 | 50 | $ ./fpc -2^7 -l-p 2^-8 51 | [PARAMETERS] 52 | min: -128 (-128 requested) 53 | max: 127.99609375 (127.99609375 requested) 54 | precision: 0.00390625 (0.00390625 requested) 55 | ... 56 | 57 | `fpc` has an expression evaluator built in to allow simple expressions! 58 | 59 | - supports (in order of precedence) 60 | - parenthesis: `(x)` 61 | - exponentiation: `x ^ y` 62 | - multiply: `x * y`, divide: `x / y` 63 | - addition: `x + y`, subtraction: `x - y` 64 | - some variables 65 | - min: `l` 66 | - max: `h` 67 | - precision: `p` -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * Fixed-point Calculator 2 | This program takes a range [min, max] and precision and calculates constants and information to be used in code performing calculations in this range using fixed-point integer math. 3 | 4 | This is not an official Google product. 5 | 6 | * Try it! 7 | #+BEGIN_EXAMPLE 8 | $ git clone ssh://git@stash.nestlabs.com:7999/user/fpc.git 9 | $ make 10 | $ ./fpc -g 30 1800 0.1 11 | [PARAMETERS] 12 | min: 30 (30 requested) 13 | max: 1800 (1800 requested) 14 | precision: 0.0625 (0.1 requested) 15 | 16 | [CODE] 17 | code density: 62.5% 18 | offset: 0 19 | code range: [480, 28800] 20 | 21 | [ENCODING] 22 | machine bit width: 16 (15 used) 23 | fractional bits: 4 24 | integer bits: 11 25 | use signed: no 26 | machine integer type: uint16_t 27 | Q notation: Qu12.4 28 | 29 | [CONVERSION] 30 | #include 31 | #include 32 | // can lose precision, for display only 33 | double convert_to_double(uint16_t x) { 34 | if(x < UINT16_C(480) && 35 | x > UINT16_C(28800)) { 36 | return NAN; 37 | } 38 | return round(ldexp(x, -4) * 10) * 0.1; 39 | } 40 | $ make convert 41 | $ ./convert 480 600 10000 28800 42 | 480 -> 30 43 | 600 -> 37.5 44 | 10000 -> 625 45 | 28800 -> 1800 46 | #+END_EXAMPLE 47 | 48 | * Also, check this out: 49 | #+BEGIN_EXAMPLE 50 | $ ./fpc -2^7 -l-p 2^-8 51 | [PARAMETERS] 52 | min: -128 (-128 requested) 53 | max: 127.99609375 (127.99609375 requested) 54 | precision: 0.00390625 (0.00390625 requested) 55 | ... 56 | #+END_EXAMPLE 57 | 58 | =fpc= has an expression evaluator built in to allow simple expressions! 59 | - supports (in order of precedence) 60 | - parenthesis: =(x)= 61 | - exponentiation: =x ^ y= 62 | - multiply: =x * y=, divide: =x / y= 63 | - addition: =x + y=, subtraction: =x - y= 64 | - some variables 65 | - min: =l= 66 | - max: =h= 67 | - precision: =p= 68 | -------------------------------------------------------------------------------- /fixnum_string.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Google Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define RADIX 10 24 | #define LOG2_RATIO 1292913986 // 2^32 * (log 2 / log RADIX) 25 | #define MAX_EXP 19 26 | #define SENTINEL (INT_MAX / RADIX) 27 | 28 | int main(int argc, char **argv) { 29 | char buf[64] = {0}; 30 | if(argc >= 2) { 31 | int exponent, mantissa; 32 | char *arg = argv[1]; 33 | int len = strlen(arg); 34 | int ret = read_float(arg, len, &exponent, &mantissa); 35 | printf("read_float(\"%s\", %d, %d, %d) = %d\n", arg, len, exponent, mantissa, ret); 36 | int fractional_bits = 16; 37 | int fixed = float_to_fixed(exponent, mantissa, fractional_bits); 38 | printf("float_to_fixed(%d, %d, %d) = %d\n", exponent, mantissa, fractional_bits, fixed); 39 | mantissa = fixed_to_float(fractional_bits, fixed, &exponent); 40 | printf("fixed_to_float(%d, %d, %d) = %d\n", fractional_bits, fixed, exponent, mantissa); 41 | ret = show_float(buf, sizeof buf - 1, exponent, mantissa); 42 | printf("show_float(\"%s\", %d, %d, %d) = %d\n", buf, (int)sizeof buf - 1, exponent, mantissa, ret); 43 | fixed = read_fixed(arg, len, fractional_bits); 44 | printf("read_fixed(\"%s\", %d, %d) = %d\n", arg, len, fractional_bits, fixed); 45 | ret = show_fixed(buf, sizeof buf - 1, fractional_bits, fixed); 46 | printf("show_fixed(\"%s\", %d, %d, %d) = %d\n", buf, (int)sizeof buf - 1, fractional_bits, fixed, ret); 47 | } 48 | return 0; 49 | } 50 | 51 | char num_to_digit(unsigned int num) { 52 | if(num < 10) { 53 | return '0' + num; 54 | } else return '?'; 55 | } 56 | 57 | int digit_to_num(char digit) { 58 | if(digit < '0') { 59 | return -1; 60 | } else if(digit <= '9') { 61 | return digit - '0'; 62 | } else { 63 | return -1; 64 | } 65 | } 66 | 67 | void reverse(char *buf, size_t size) { 68 | char 69 | *left = buf, 70 | *right = buf + size - 1, 71 | tmp; 72 | 73 | while(left < right) { 74 | tmp = *left; 75 | *left = *right; 76 | *right = tmp; 77 | left++; 78 | right--; 79 | } 80 | } 81 | 82 | int read_float(char *buf, size_t size, int *exponent_out, int *mantissa_out) { 83 | int mantissa = 0; 84 | int exponent = 0; 85 | bool neg = false; 86 | char *cursor = buf; 87 | char *end = buf + size; 88 | 89 | // sign 90 | if(cursor < end && *cursor == '-') { 91 | neg = true; 92 | cursor++; 93 | } 94 | 95 | // whole part 96 | while(cursor < end) { 97 | int digit = digit_to_num(*cursor); 98 | if(digit < 0) break; 99 | if(mantissa >= SENTINEL) return -EOVERFLOW; 100 | mantissa *= RADIX; 101 | mantissa += digit; 102 | cursor++; 103 | } 104 | 105 | // fractional part 106 | if(cursor < end && *cursor == '.') { 107 | cursor++; 108 | while(cursor < end) { 109 | int digit = digit_to_num(*cursor); 110 | if(digit < 0) break; 111 | if(mantissa >= SENTINEL) return -EOVERFLOW; 112 | mantissa *= RADIX; 113 | mantissa += digit; 114 | cursor++; 115 | exponent--; 116 | } 117 | } 118 | *exponent_out = exponent; 119 | *mantissa_out = neg ? -mantissa : mantissa; 120 | return cursor - buf; 121 | } 122 | 123 | int show_float(char *buf, size_t size, int exponent, int mantissa) { 124 | int n = mantissa < 0 ? -mantissa : mantissa; 125 | char *cursor = buf; 126 | char *end = buf + size; 127 | if(exponent >= 0) exponent = 1; 128 | 129 | // remove trailing zeroes 130 | while(exponent < 0 && n % RADIX == 0) { 131 | n /= RADIX; 132 | exponent++; 133 | } 134 | 135 | // fractional part 136 | if(exponent < 0) { 137 | 138 | while(exponent < 0) { 139 | if(cursor >= end) return -EOVERFLOW; 140 | *cursor++ = num_to_digit(n % RADIX); 141 | n /= RADIX; 142 | exponent++; 143 | } 144 | 145 | if(cursor >= end) return -EOVERFLOW; 146 | *cursor++ = '.'; 147 | } 148 | 149 | // whole part 150 | do { 151 | if(cursor >= end) return -EOVERFLOW; 152 | *cursor++ = num_to_digit(n % RADIX); 153 | n /= RADIX; 154 | exponent++; 155 | } while(n); 156 | 157 | // sign 158 | if(mantissa < 0) { 159 | if(cursor >= end) return -EOVERFLOW; 160 | *cursor++ = '-'; 161 | } 162 | 163 | // flip it 164 | int written = cursor - buf; 165 | reverse(buf, written); 166 | 167 | // add a null terminator 168 | if(cursor >= end) return -EOVERFLOW; 169 | *cursor = 0; 170 | 171 | return written; 172 | } 173 | 174 | #define SQUARED(X) ((unsigned long)(X) * (X)) 175 | #define RADIX2 SQUARED(RADIX) 176 | #define RADIX4 SQUARED(RADIX2) 177 | #define RADIX8 SQUARED(RADIX4) 178 | #define RADIX16 SQUARED(RADIX8) 179 | uint64_t exp_radix(unsigned int n) { 180 | int64_t x = 1; 181 | if(n > MAX_EXP) return 0; 182 | if(n >= 16) { 183 | x *= RADIX16; 184 | n -= 16; 185 | } 186 | if(n >= 8) { 187 | x *= RADIX8; 188 | n -= 8; 189 | } 190 | if(n >= 4) { 191 | x *= RADIX4; 192 | n -= 4; 193 | } 194 | if(n >= 2) { 195 | x *= RADIX2; 196 | n -= 2; 197 | } 198 | if(n >= 1) { 199 | x *= RADIX; 200 | n -= 1; 201 | } 202 | return x; 203 | } 204 | 205 | #define SIGN(x, y) ((x) < 0 ? -(y) : (y)) 206 | #define ROUND(type, frac, x) (((x) + SIGN((x), (1 << ((frac) - 1)))) >> (frac)) 207 | #define CEILING(type, frac, x) (((x) + (((type)1) << (frac)) - 1) >> (frac)) 208 | 209 | int32_t float_to_fixed(int exponent, int32_t mantissa, unsigned int fractional_bits) { 210 | int64_t fixed = (int64_t)mantissa << fractional_bits; 211 | if(exponent < 0) { 212 | int64_t divisor = exp_radix(-exponent) / 2; 213 | fixed /= divisor; 214 | fixed = (fixed + SIGN(mantissa, 1)) / 2; 215 | } else { 216 | fixed *= exp_radix(exponent); 217 | } 218 | return fixed; 219 | } 220 | 221 | int fixed_to_float(unsigned int fractional_bits, int32_t fixed, int *exponent_out) { 222 | int exponent = CEILING(uint64_t, 32, (uint64_t)fractional_bits * LOG2_RATIO); 223 | int floating = ROUND(int64_t, fractional_bits, fixed * exp_radix(exponent)); 224 | 225 | // trim zeroes 226 | while(floating % RADIX == 0 && exponent > 0) { 227 | exponent--; 228 | floating /= RADIX; 229 | } 230 | 231 | *exponent_out = -exponent; 232 | return floating; 233 | } 234 | 235 | int read_fixed(char *buf, size_t size, unsigned int fractional_bits) { 236 | int ret; 237 | int mantissa, exponent; 238 | 239 | ret = read_float(buf, size, &mantissa, &exponent); 240 | 241 | if(ret < 0) 242 | return 0; 243 | 244 | return float_to_fixed(mantissa, exponent, fractional_bits); 245 | } 246 | 247 | int show_fixed(char *buf, size_t size, unsigned int fractional_bits, int fixed) { 248 | int ret; 249 | int mantissa, exponent; 250 | 251 | mantissa = fixed_to_float(fractional_bits, fixed, &exponent); 252 | return show_float(buf, size, exponent, mantissa); 253 | } 254 | -------------------------------------------------------------------------------- /fpc.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Google Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include "fpc.h" 19 | 20 | #define LENGTH(x) (sizeof(x)/sizeof(x[0])) 21 | 22 | static 23 | int floor_log2l(long double x) { 24 | int exp; 25 | frexpl(x, &exp); 26 | return exp - 1; 27 | } 28 | 29 | static 30 | unsigned int int_log2(unsigned int x) { 31 | return x <= 1 ? 0 : (8 * sizeof(x)) - __builtin_clz(x - 1); 32 | } 33 | 34 | static 35 | int clz128(int128_t x) { 36 | unsigned int y; 37 | unsigned int shift = sizeof(y) * 8; 38 | int i, n = sizeof(x) / sizeof(y); 39 | for(i = 0; i < n; i++) { 40 | y = x >> (shift * (n - 1 - i)); 41 | if(y) return __builtin_clz(y) + shift * i; 42 | } 43 | return shift * n; 44 | } 45 | 46 | static 47 | unsigned int int128_log2(int128_t x) { 48 | return x <= 1 ? 0 : 128 - clz128(x - 1); 49 | } 50 | 51 | bool fpc_calculate(struct fpc_parameters *param) { 52 | if(param->max < param->min + param->precision) { 53 | param->error = "max < min + precision"; 54 | return false; 55 | } 56 | if(param->precision <= 0.0L) { 57 | param->error = "zero or negative precision"; 58 | return false; 59 | } 60 | param->fractional_bits = -floor_log2l(param->precision); 61 | param->lower_bound = ceill(ldexpl(param->min - param->precision / 2, param->fractional_bits)); 62 | param->upper_bound = floorl(ldexpl(param->max + param->precision / 2, param->fractional_bits)); 63 | 64 | param->fixed_encoding_width = int128_log2(param->upper_bound - param->lower_bound + 1); 65 | param->integer_bits = param->fixed_encoding_width - param->fractional_bits; 66 | 67 | if(param->fixed_encoding_width > 64) { 68 | param->error = "fixed_encoding_width > 64"; 69 | return false; 70 | } 71 | if(param->fixed_encoding_width < 8) { // could disable this lower bound to support packed formats 72 | param->fixed_encoding_width = 8; 73 | } else { 74 | param->fixed_encoding_width = 1 << int_log2(param->fixed_encoding_width); 75 | } 76 | param->offset = param->lower_bound; 77 | param->large_offset = false; 78 | if(param->offset > (((int128_t)1) << 63) - 1 || 79 | param->offset < -(((int128_t)1) << 63)) { 80 | param->large_offset = true; 81 | } 82 | param->use_signed = false; 83 | if(param->min < 0.0L) { 84 | if(param->upper_bound <= (((int128_t)1) << (param->fixed_encoding_width - 1)) - 1 && 85 | param->lower_bound >= (((int128_t)-1) << (param->fixed_encoding_width - 1))) { 86 | param->offset = 0; 87 | param->use_signed = true; 88 | } 89 | } else { 90 | if(param->upper_bound <= (((int128_t)1) << param->fixed_encoding_width) - 1) { 91 | param->offset = 0; 92 | } 93 | } 94 | return true; 95 | } 96 | 97 | static 98 | const char *get_op(char c) { 99 | static const char *ops = "+a-a*b/b^c(())"; 100 | const char *op = ops; 101 | while(*op) { 102 | if(*op == c) { 103 | return op; 104 | } 105 | op += 2; 106 | } 107 | return NULL; 108 | } 109 | 110 | static char vars[16]; 111 | static long double values[sizeof(vars)]; 112 | static unsigned int n_vars = 0; 113 | 114 | void fpc_set_var(char c, long double x) { 115 | if(n_vars < sizeof(vars)) { 116 | int n = n_vars++; 117 | vars[n] = c; 118 | values[n] = x; 119 | } 120 | } 121 | 122 | long double *fpc_get_var(char c) { 123 | char *v = strchr(vars, c); 124 | return v ? &values[v - vars] : NULL; 125 | } 126 | 127 | static 128 | bool do_op(char op, long double *arg) { 129 | switch(op) { 130 | case '+': arg[0] += arg[1]; break; 131 | case '-': arg[0] -= arg[1]; break; 132 | case '*': arg[0] *= arg[1]; break; 133 | case '/': arg[0] /= arg[1]; break; 134 | case '^': arg[0] = powl(arg[0], arg[1]); break; 135 | case '(': return false; 136 | default: arg[0] = NAN; break; 137 | } 138 | return true; 139 | } 140 | 141 | static 142 | long double parse_num(char **pstr) { 143 | char *p = *pstr; 144 | long double val = strtold(*pstr, pstr); 145 | if(*pstr != p) return val; 146 | (*pstr)++; 147 | long double *var = fpc_get_var(*p); 148 | return var ? *var : NAN; 149 | } 150 | 151 | /* expression parser based on the shunting-yard algorithm */ 152 | long double fpc_eval_expr(char *str) { 153 | long double args[32]; 154 | const char *ops[32]; 155 | unsigned int arg_top = 0; 156 | unsigned int op_top = 0; 157 | bool expect_num = true; 158 | char *p = str; 159 | const char *op; 160 | while(*p) { 161 | while(*p == ' ') p++; 162 | op = get_op(*p); 163 | while(*p == ' ') p++; 164 | if(!op) { 165 | if(!expect_num) return NAN; 166 | if(arg_top >= LENGTH(args)) return NAN; 167 | args[arg_top++] = parse_num(&p); 168 | expect_num = false; 169 | } else if(*op == '(') { 170 | p++; 171 | if(!expect_num) return NAN; 172 | ops[op_top++] = op; 173 | } else { 174 | p++; 175 | if(expect_num) { 176 | if(*op == '-') { 177 | args[arg_top++] = -1.0L; 178 | op += 2; 179 | goto checks; 180 | } else return NAN; 181 | } 182 | while(op_top && 183 | op[1] <= (ops[op_top - 1])[1] && 184 | do_op(*(ops[op_top - 1]), &args[arg_top - 2])) { 185 | arg_top--; 186 | op_top--; 187 | } 188 | checks: 189 | if(*op == ')') { 190 | if(!op_top) return NAN; 191 | op_top--; 192 | expect_num = false; 193 | } else { 194 | if(op_top >= LENGTH(ops)) return NAN; 195 | ops[op_top++] = op; 196 | expect_num = true; 197 | } 198 | } 199 | } 200 | if(expect_num) return NAN; 201 | while(op_top && 202 | do_op(*(ops[op_top - 1]), &args[arg_top - 2])) { 203 | arg_top--; 204 | op_top--; 205 | } 206 | if(op_top) return NAN; 207 | return args[0]; 208 | } 209 | 210 | bool fpc_calculate_from_strings(char *min, 211 | char *max, 212 | char *precision, 213 | struct fpc_parameters *param) { 214 | struct entry { 215 | char *expr; 216 | long double *dest; 217 | char var; 218 | bool complete; 219 | } entries[] = { 220 | { .expr = min, .dest = ¶m->min, .var = 'l'}, 221 | { .expr = max, .dest = ¶m->max, .var = 'h'}, 222 | { .expr = precision, .dest = ¶m->precision, .var = 'p'} 223 | }; 224 | 225 | unsigned int i, left = LENGTH(entries); 226 | bool progress; 227 | do { 228 | progress = false; 229 | for(i = 0; i < LENGTH(entries); i++) { 230 | struct entry *e = &entries[i]; 231 | if(e->complete) continue; 232 | long double x = fpc_eval_expr(e->expr); 233 | if(!isnan(x)) { 234 | progress = true; 235 | left--; 236 | e->complete = true; 237 | *(e->dest) = x; 238 | fpc_set_var(e->var, x); 239 | } 240 | } 241 | } while(left && progress); 242 | return fpc_calculate(param); 243 | } 244 | -------------------------------------------------------------------------------- /fpc.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Google Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. */ 14 | 15 | #ifndef __FPC__ 16 | #define __FPC__ 17 | 18 | #include 19 | 20 | typedef __int128_t int128_t; 21 | 22 | /* data structure for holding parameters and calculated values */ 23 | struct fpc_parameters { 24 | /* these are the inputs */ 25 | long double 26 | min, 27 | max, 28 | precision; 29 | 30 | /* these can use more than fixed_encoding_width since there can be a _really_ large offset */ 31 | int128_t 32 | lower_bound, 33 | upper_bound, 34 | offset; 35 | 36 | int 37 | fractional_bits, 38 | integer_bits, 39 | fixed_encoding_width; 40 | 41 | bool 42 | use_signed, 43 | large_offset; 44 | 45 | const char *error; 46 | }; 47 | 48 | /* given an fpc_parameters struct with min, max, precision, 49 | calculate the other members */ 50 | bool fpc_calculate(struct fpc_parameters *param); 51 | 52 | /* a simple expression evaluator 53 | supports (in order of precedence) 54 | - parenthesis: `(x)` 55 | - exponentiation: `x ^ y` 56 | - multiply: `x * y`, divide: `x / y` 57 | - addition: `x + y`, subtraction: `x - y` 58 | add variables with fpc_set_var() 59 | */ 60 | long double fpc_eval_expr(char *str); 61 | 62 | /* set a single letter variable for use in fpc_eval_expr() expressions */ 63 | void fpc_set_var(char c, long double x); 64 | 65 | /* get a variable */ 66 | long double *fpc_get_var(char c); 67 | 68 | /* alternative to fpc_calculate that takes string expressions 69 | defines the following variables: 70 | - l = min 71 | - h = max 72 | - p = precision 73 | */ 74 | bool fpc_calculate_from_strings(char *min, 75 | char *max, 76 | char *precision, 77 | struct fpc_parameters *param); 78 | 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Google Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "fpc.h" 21 | 22 | #define max(x, y) ((y) > (x) ? (y) : (x)) 23 | 24 | static 25 | void convert_to_double(struct fpc_parameters *param, FILE *f) { 26 | #define printf(...) fprintf(f, __VA_ARGS__) 27 | int128_t 28 | lb = param->lower_bound - param->offset, 29 | ub = param->upper_bound - param->offset, 30 | min_int = param->use_signed ? -(1 << (param->fixed_encoding_width - 1)) : 0, 31 | max_int = (1 << (param->fixed_encoding_width - (param->use_signed ? 1 : 0))) - 1; 32 | printf("double convert_to_double(%s%d_t x) {\n", 33 | param->use_signed ? "int" : "uint", param->fixed_encoding_width); 34 | 35 | // Check bounds 36 | if(lb != min_int || ub != max_int) { 37 | printf(" if("); 38 | if(lb != min_int) { 39 | printf("x < %s%d_C(%lld)", 40 | param->use_signed ? "INT" : "UINT", 41 | param->fixed_encoding_width, 42 | (long long int)lb); 43 | if(ub != max_int) printf(" ||\n "); 44 | } 45 | if(ub != max_int) { 46 | printf("x > %s%d_C(%lld)", 47 | param->use_signed ? "INT" : "UINT", 48 | param->fixed_encoding_width, 49 | (long long int)ub); 50 | } 51 | printf(") {\n" 52 | " return NAN;\n" 53 | " }\n"); 54 | } 55 | 56 | printf(" return "); 57 | if(param->precision != 1.0l) { 58 | printf("round("); 59 | } 60 | if(param->offset) printf("("); 61 | if(param->fractional_bits) { 62 | printf("ldexp(x, %d)", -param->fractional_bits); 63 | } else { 64 | printf("x"); 65 | } 66 | if(param->offset) { 67 | printf(" + %.19Lg)", ldexpl(param->offset, -param->fractional_bits)); 68 | } 69 | if(param->precision != 1.0L) { 70 | printf(" * %.19Lg) * %.19Lg", 71 | 1.0L / param->precision, 72 | param->precision); 73 | } 74 | printf(";\n"); 75 | 76 | printf("}\n"); 77 | #undef printf 78 | } 79 | 80 | static 81 | void convert_from_double(struct fpc_parameters *param, FILE *f) { 82 | #define printf(...) fprintf(f, __VA_ARGS__) 83 | printf("bool convert_from_double(double x, %s%d_t *y) {\n", 84 | param->use_signed ? "int" : "uint", param->fixed_encoding_width); 85 | 86 | // Check bounds 87 | printf(" if(x < %Lg || x > %Lg) {\n", param->min, param->max); 88 | printf(" return false;\n" 89 | " } else {\n"); 90 | printf(" *y = round(ldexp(x, %d))", param->fractional_bits); 91 | if(param->offset != 0) { 92 | printf(" - %.19Lg", (long double)param->offset); 93 | } 94 | printf(";\n"); 95 | printf(" return true;\n" 96 | " }\n" 97 | "}\n"); 98 | 99 | #undef printf 100 | } 101 | 102 | static 103 | void print_params(struct fpc_parameters *param) { 104 | printf("[PARAMETERS]\n"); 105 | printf(" min: %.19Lg (%.19Lg requested)\n", 106 | ldexpl(param->lower_bound, -param->fractional_bits), 107 | param->min); 108 | printf(" max: %.19Lg (%.19Lg requested)\n", 109 | ldexpl(param->upper_bound, -param->fractional_bits), 110 | param->max); 111 | long double actual_precision = ldexpl(1.0L, -param->fractional_bits); 112 | printf(" precision: %.19Lg (%.19Lg requested)\n", 113 | actual_precision, 114 | param->precision); 115 | printf("\n[CODE]\n"); 116 | printf(" code density: %.1Lf%%\n", 100L * actual_precision / param->precision); 117 | if(param->large_offset) { 118 | printf(" offset: about %.19Lg\n", (long double)param->offset); 119 | } else { 120 | printf(" offset: %" PRId64 "\n", (int64_t)param->offset); 121 | } 122 | printf(" code range: [%" PRId64 ", %" PRId64 "]\n", 123 | (int64_t)(param->lower_bound - param->offset), 124 | (int64_t)(param->upper_bound - param->offset)); 125 | printf("\n[ENCODING]\n"); 126 | printf(" machine bit width: %d (%d used)\n", param->fixed_encoding_width, param->integer_bits + param->fractional_bits); 127 | printf(" fractional bits: %d\n", param->fractional_bits); 128 | printf(" integer bits: %d\n", param->integer_bits); 129 | printf(" use signed: %s\n", param->use_signed ? "yes" : "no"); 130 | printf(" machine integer type: %s%d_t\n", param->use_signed ? "int" : "uint", param->fixed_encoding_width); 131 | printf(" Q notation: Q%c%d.%d\n", param->use_signed ? 's' : 'u', param->fixed_encoding_width - param->fractional_bits - (param->use_signed ? 1 : 0), param->fractional_bits); 132 | printf("\n[CONVERSION]\n"); 133 | convert_to_double(param, stdout); 134 | printf("\n"); 135 | convert_from_double(param, stdout); 136 | } 137 | 138 | static 139 | void gen_converter(struct fpc_parameters *param) { 140 | FILE *f = fopen("convert.c", "w"); 141 | fprintf(f, 142 | "#include \n" 143 | "#include \n" 144 | "#include \n" 145 | "#include \n" 146 | "#include \n" 147 | "#include \n\n"); 148 | convert_to_double(param, f); 149 | fprintf(f, "\n"); 150 | convert_from_double(param, f); 151 | fprintf(f, 152 | "\n" 153 | "int main(int argc, char **argv) {\n" 154 | " int i;\n" 155 | " argv++; argc--; // skip first arg\n" 156 | " for(i = 0; i < argc; i++) {\n" 157 | " char *s = argv[i];\n" 158 | " if(strchr(s, '.')) {\n" 159 | " double x = strtod(s, &s);\n" 160 | " %s%d_t y;\n" 161 | " if(convert_from_double(x, &y)) {\n" 162 | " printf(\"float %%.15g -> fixed %%ld\\n\", x, (long int)y);\n" 163 | " } else {\n" 164 | " printf(\"float %%.15g -> ERROR\\n\", x);\n" 165 | " }\n" 166 | " } else {\n" 167 | " long int x = strtol(s, NULL, 10);\n" 168 | " printf(\"fixed %%ld -> float %%.15g\\n\", x, convert_to_double(x));\n" 169 | " }\n" 170 | " }\n" 171 | " return 0;\n" 172 | "}\n", 173 | param->use_signed ? "int" : "uint", param->fixed_encoding_width); 174 | fclose(f); 175 | } 176 | 177 | int main(int argc, char **argv) { 178 | struct fpc_parameters param; 179 | memset(¶m, 0, sizeof(param)); 180 | bool gen = false; 181 | 182 | if(argc == 2) { 183 | // simple expression evaluator 184 | printf("%.19Lg\n", fpc_eval_expr(argv[1])); 185 | return 0; 186 | } 187 | 188 | if(argc <= 3) { 189 | printf("fpc [min] [max] [precision]\n"); 190 | return -1; 191 | } 192 | 193 | if(strcmp(argv[1], "-g") == 0) { 194 | gen = true; 195 | argv++; 196 | } 197 | 198 | if(fpc_calculate_from_strings(argv[1], argv[2], argv[3], ¶m)) { 199 | print_params(¶m); 200 | if(gen) gen_converter(¶m); 201 | return 0; 202 | } else { 203 | fprintf(stderr, "ERROR: %s\n", param.error); 204 | return -1; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /test_output.txt: -------------------------------------------------------------------------------- 1 | 2 | ___[ fpc -256 -l-p 0.01 ]___ 3 | [PARAMETERS] 4 | min: -256 (-256 requested) 5 | max: 255.9921875 (255.99 requested) 6 | precision: 0.0078125 (0.01 requested) 7 | 8 | [CODE] 9 | code density: 78.1% 10 | offset: 0 11 | code range: [-32768, 32767] 12 | 13 | [ENCODING] 14 | machine bit width: 16 (16 used) 15 | fractional bits: 7 16 | integer bits: 9 17 | use signed: yes 18 | machine integer type: int16_t 19 | Q notation: Qs8.7 20 | 21 | [CONVERSION] 22 | double convert_to_double(int16_t x) { 23 | return round(ldexp(x, -7) * 100) * 0.01; 24 | } 25 | 26 | bool convert_from_double(double x, int16_t *y) { 27 | if(x < -256 || x > 255.99) { 28 | return false; 29 | } else { 30 | *y = round(ldexp(x, 7)); 31 | return true; 32 | } 33 | } 34 | 35 | ___[ fpc -512 -l-p 1 ]___ 36 | [PARAMETERS] 37 | min: -512 (-512 requested) 38 | max: 511 (511 requested) 39 | precision: 1 (1 requested) 40 | 41 | [CODE] 42 | code density: 100.0% 43 | offset: 0 44 | code range: [-512, 511] 45 | 46 | [ENCODING] 47 | machine bit width: 16 (10 used) 48 | fractional bits: 0 49 | integer bits: 10 50 | use signed: yes 51 | machine integer type: int16_t 52 | Q notation: Qs15.0 53 | 54 | [CONVERSION] 55 | double convert_to_double(int16_t x) { 56 | if(x < INT16_C(-512) || 57 | x > INT16_C(511)) { 58 | return NAN; 59 | } 60 | return x; 61 | } 62 | 63 | bool convert_from_double(double x, int16_t *y) { 64 | if(x < -512 || x > 511) { 65 | return false; 66 | } else { 67 | *y = round(ldexp(x, 0)); 68 | return true; 69 | } 70 | } 71 | 72 | ___[ fpc 2^70 l+256 1 ]___ 73 | [PARAMETERS] 74 | min: 1.180591620717411303e+21 (1.180591620717411303e+21 requested) 75 | max: 1.180591620717411304e+21 (1.180591620717411304e+21 requested) 76 | precision: 1 (1 requested) 77 | 78 | [CODE] 79 | code density: 100.0% 80 | offset: about 1.180591620717411303e+21 81 | code range: [0, 256] 82 | 83 | [ENCODING] 84 | machine bit width: 16 (9 used) 85 | fractional bits: 0 86 | integer bits: 9 87 | use signed: no 88 | machine integer type: uint16_t 89 | Q notation: Qu16.0 90 | 91 | [CONVERSION] 92 | double convert_to_double(uint16_t x) { 93 | if(x > UINT16_C(256)) { 94 | return NAN; 95 | } 96 | return (x + 1.180591620717411303e+21); 97 | } 98 | 99 | bool convert_from_double(double x, uint16_t *y) { 100 | if(x < 1.18059e+21 || x > 1.18059e+21) { 101 | return false; 102 | } else { 103 | *y = round(ldexp(x, 0)) - 1.180591620717411303e+21; 104 | return true; 105 | } 106 | } 107 | 108 | ___[ fpc 1 2 3 ]___ 109 | ERROR: max < min + precision 110 | 111 | ___[ fpc 2 1 1 ]___ 112 | ERROR: max < min + precision 113 | 114 | ___[ fpc 1 2 0 ]___ 115 | ERROR: zero or negative precision 116 | 117 | ___[ fpc 1+2*3^4 ]___ 118 | 163 119 | 120 | ___[ fpc (1+2)*3 ]___ 121 | 9 122 | 123 | ___[ fpc (1*1)+99 ]___ 124 | 100 125 | 126 | ___[ fpc -2^7 ]___ 127 | -128 128 | 129 | ___[ fpc -h-p 2^8-p 0.01 ]___ 130 | [PARAMETERS] 131 | min: -256 (-256 requested) 132 | max: 255.9921875 (255.99 requested) 133 | precision: 0.0078125 (0.01 requested) 134 | 135 | [CODE] 136 | code density: 78.1% 137 | offset: 0 138 | code range: [-32768, 32767] 139 | 140 | [ENCODING] 141 | machine bit width: 16 (16 used) 142 | fractional bits: 7 143 | integer bits: 9 144 | use signed: yes 145 | machine integer type: int16_t 146 | Q notation: Qs8.7 147 | 148 | [CONVERSION] 149 | double convert_to_double(int16_t x) { 150 | return round(ldexp(x, -7) * 100) * 0.01; 151 | } 152 | 153 | bool convert_from_double(double x, int16_t *y) { 154 | if(x < -256 || x > 255.99) { 155 | return false; 156 | } else { 157 | *y = round(ldexp(x, 7)); 158 | return true; 159 | } 160 | } 161 | 162 | ___[ fpc -2^63 -l-p 1 ]___ 163 | [PARAMETERS] 164 | min: -9223372036854775808 (-9223372036854775808 requested) 165 | max: 9223372036854775807 (9223372036854775807 requested) 166 | precision: 1 (1 requested) 167 | 168 | [CODE] 169 | code density: 100.0% 170 | offset: 0 171 | code range: [-9223372036854775808, 9223372036854775807] 172 | 173 | [ENCODING] 174 | machine bit width: 64 (64 used) 175 | fractional bits: 0 176 | integer bits: 64 177 | use signed: yes 178 | machine integer type: int64_t 179 | Q notation: Qs63.0 180 | 181 | [CONVERSION] 182 | double convert_to_double(int64_t x) { 183 | if(x < INT64_C(-9223372036854775808) || 184 | x > INT64_C(9223372036854775807)) { 185 | return NAN; 186 | } 187 | return x; 188 | } 189 | 190 | bool convert_from_double(double x, int64_t *y) { 191 | if(x < -9.22337e+18 || x > 9.22337e+18) { 192 | return false; 193 | } else { 194 | *y = round(ldexp(x, 0)); 195 | return true; 196 | } 197 | } 198 | 199 | ___[ fpc -2^63 -l 1 ]___ 200 | ERROR: fixed_encoding_width > 64 201 | 202 | ___[ fpc 2^-7 ]___ 203 | 0.0078125 204 | 205 | ___[ fpc -(1) ]___ 206 | -1 207 | 208 | ___[ fpc -2^-(2) ]___ 209 | -0.25 210 | -------------------------------------------------------------------------------- /tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2016 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | fpc() { 18 | echo 19 | echo ___[ fpc $@ ]___ 20 | ./fpc $@ 21 | } 22 | 23 | fpc -256 -l-p 0.01 24 | fpc -512 -l-p 1 25 | fpc 2^70 l+256 1 26 | fpc 1 2 3 27 | fpc 2 1 1 28 | fpc 1 2 0 29 | fpc 1+2*3^4 30 | fpc '(1+2)*3' 31 | fpc '(1*1)+99' 32 | fpc -2^7 33 | fpc -h-p 2^8-p 0.01 34 | fpc -2^63 -l-p 1 35 | fpc -2^63 -l 1 36 | fpc 2^-7 37 | fpc '-(1)' 38 | fpc '-2^-(2)' 39 | 40 | exit 0 41 | --------------------------------------------------------------------------------