/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _DALVIK_FLOAT12_H #define _DALVIK_FLOAT12_H /* Encodes a 32-bit number in 12 bits with +/-1.5% error, * though the majority (80%) are within +/-0.25%. * * The encoding looks like: * * EEEMMMMM MMMMMMMM MMMMMMMM * 76543210 76543210 76543210 * * where EEE is a base-16 exponent and MMMM is the mantissa. * The output value is (MMMM * 16^EEE), or (MMMM << (EEE * 4)). * * TODO: do this in a less brain-dead way. I'm sure we can do * it without all of these loops. */ inline unsigned short intToFloat12(unsigned int val) { int oval = val; int shift = 0; /* Shift off the precision we don't care about. * Don't round here; it biases the values too high * (such that the encoded value is always greater * than the actual value) */ unsigned int pval = val; while (val > 0x1ff) { pval = val; val >>= 1; shift++; } if (shift > 0 && (pval & 1)) { /* Round based on the last bit we shifted off. */ val++; if (val > 0x1ff) { val = (val + 1) >> 1; shift++; } } /* Shift off enough bits to create a valid exponent. * Since we care about the bits we're losing, be sure * to round them. */ while (shift % 4 != 0) { val = (val + 1) >> 1; shift++; } /* In the end, only round by the most-significant lost bit. * This centers the values around the closest match. * All of the rounding we did above guarantees that this * round won't overflow past 0x1ff. */ if (shift > 0) { val = ((oval >> (shift - 1)) + 1) >> 1; } val |= (shift / 4) << 9; return val; } inline unsigned int float12ToInt(unsigned short f12) { return (f12 & 0x1ff) << ((f12 >> 9) * 4); } #if 0 // testing #include <stdio.h> int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "usage: %s <min> <max>\n", argv[0]); return 1; } unsigned int min = atoi(argv[1]); unsigned int max = atoi(argv[2]); if (min > max) { int t = min; max = min; min = t; } else if (min == max) { max++; } while (min < max) { unsigned int out; unsigned short sf; sf = intToFloat12(min); out = float12ToInt(sf); // printf("%d 0x%03x / 0x%03x %d (%d)\n", min, min, sf, out, (int)min - (int)out); printf("%6.6f %d %d\n", ((float)(int)(min - out)) / (float)(int)min, min, out); if (min <= 8192) { min++; } else if (min < 10000) { min += 10; } else if (min < 100000) { min += 1000; } else { min += 10000; } } return 0; } #endif // testing #endif // _DALVIK_FLOAT12_H