/*
* 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