1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _DALVIK_FLOAT12_H 18 #define _DALVIK_FLOAT12_H 19 20 /* Encodes a 32-bit number in 12 bits with +/-1.5% error, 21 * though the majority (80%) are within +/-0.25%. 22 * 23 * The encoding looks like: 24 * 25 * EEEMMMMM MMMMMMMM MMMMMMMM 26 * 76543210 76543210 76543210 27 * 28 * where EEE is a base-16 exponent and MMMM is the mantissa. 29 * The output value is (MMMM * 16^EEE), or (MMMM << (EEE * 4)). 30 * 31 * TODO: do this in a less brain-dead way. I'm sure we can do 32 * it without all of these loops. 33 */ 34 inline unsigned short intToFloat12(unsigned int val) 35 { 36 int oval = val; 37 int shift = 0; 38 39 /* Shift off the precision we don't care about. 40 * Don't round here; it biases the values too high 41 * (such that the encoded value is always greater 42 * than the actual value) 43 */ 44 unsigned int pval = val; 45 while (val > 0x1ff) { 46 pval = val; 47 val >>= 1; 48 shift++; 49 } 50 if (shift > 0 && (pval & 1)) { 51 /* Round based on the last bit we shifted off. 52 */ 53 val++; 54 if (val > 0x1ff) { 55 val = (val + 1) >> 1; 56 shift++; 57 } 58 } 59 60 /* Shift off enough bits to create a valid exponent. 61 * Since we care about the bits we're losing, be sure 62 * to round them. 63 */ 64 while (shift % 4 != 0) { 65 val = (val + 1) >> 1; 66 shift++; 67 } 68 69 /* In the end, only round by the most-significant lost bit. 70 * This centers the values around the closest match. 71 * All of the rounding we did above guarantees that this 72 * round won't overflow past 0x1ff. 73 */ 74 if (shift > 0) { 75 val = ((oval >> (shift - 1)) + 1) >> 1; 76 } 77 78 val |= (shift / 4) << 9; 79 return val; 80 } 81 82 inline unsigned int float12ToInt(unsigned short f12) 83 { 84 return (f12 & 0x1ff) << ((f12 >> 9) * 4); 85 } 86 87 #if 0 // testing 88 89 #include <stdio.h> 90 int main(int argc, char *argv[]) 91 { 92 if (argc != 3) { 93 fprintf(stderr, "usage: %s <min> <max>\n", argv[0]); 94 return 1; 95 } 96 97 unsigned int min = atoi(argv[1]); 98 unsigned int max = atoi(argv[2]); 99 if (min > max) { 100 int t = min; 101 max = min; 102 min = t; 103 } else if (min == max) { 104 max++; 105 } 106 107 while (min < max) { 108 unsigned int out; 109 unsigned short sf; 110 111 sf = intToFloat12(min); 112 out = float12ToInt(sf); 113 // printf("%d 0x%03x / 0x%03x %d (%d)\n", min, min, sf, out, (int)min - (int)out); 114 printf("%6.6f %d %d\n", ((float)(int)(min - out)) / (float)(int)min, min, out); 115 if (min <= 8192) { 116 min++; 117 } else if (min < 10000) { 118 min += 10; 119 } else if (min < 100000) { 120 min += 1000; 121 } else { 122 min += 10000; 123 } 124 } 125 return 0; 126 } 127 128 #endif // testing 129 130 #endif // _DALVIK_FLOAT12_H 131