c - 除以和随后与相同 float 的乘法

标签 c floating-point type-conversion precision floating-accuracy

以下代码对相同浮点数除以和后续乘法的行为进行了经验分析。

在不四舍五入的情况下查看程序的输出时,这种行为对我来说似乎有些随意。我期待一个不那么紧张的 react 。我现在的问题是:任何人都可以制定某种规则来解释结果或提供其他某种深刻的见解,也许也适用于四舍五入的情况。

我知道 this post ,这与 b = 1 的特殊情况有关。

为简单起见,我建议将答案限制在 IEEE-754 32 位单精度 float (和 32 位 unsigned int ,这在这里并不重要)。

我是如何遇到这个话题的:假设有一个 8 位灰度图像(unsigned char 而不是 unsigned int 在这种情况下)并将其转换为 32 位 float图像,从而除以 b = 255.0f 以便将 {0, 1, ..., 255} 映射到区间 [0, 1]。现在当通过乘以 255.0f 转换回 {0, 1, ..., 255} 时,会遇到不精确吗?根据我的经验分析,答案是否定的(请参阅下面不四舍五入的输出,1023 超过 255),但是例如对于 252.0f,答案是肯定的。当然可以通过添加 0.5f 来处理这个问题,以便在转换回 unsigned char 时进行舍入。 - 对于一般情况,无论如何都应该这样做,因为通常转换回浮点图像的处理版本而不是未触及的版本。不过,我开始怀疑是否可以在未触及的情况下省略为舍入添加 0.5f。

#include <limits.h>
#include <stdio.h>

unsigned int foo(float b) {
    unsigned int a;

    for (a = 0; a < UINT_MAX; a++) {
        unsigned int a_ = (float) a / b * b; // without rounding
        //unsigned int a_ = (float) a / b * b + 0.5f; // with rounding

        if (a_ != a) {
            break;
        }
    }

    return a;
}

int main() {
    for (unsigned int b = 1; b < 256; b++) {
        printf("%u:%u, ", b, foo((float) b));
    }

    return 0;
}

不四舍五入的输出:1:16777217, 2:16777217, 3:12582913, 4:16777217, 5:10485763, 6:12582913, 7:31, 8:16777217, 9:9437189, 10:10485763, 11:13, 12:12582913, 13:53, 14:31, 15:63, 16:16777217, 17:8912905, 18:9437189, 19:27, 20:10485763, 21:57, 22:13, 23:7, 24:12582913, 25:53, 26:53, 27:29, 28:31, 29:15, 30:63, 31:997, 32:16777217, 33:8650769, 34:8912905, 35:103, 36:9437189, 37:3, 38:27, 39:107, 40:10485763, 41:1, 42:57, 43:15, 44:13, 45:113, 46:7, 47:1, 48:12582913, 49:27, 50:53, 51:119, 52:53, 53:15, 54:29, 55:1, 56:31, 57:63, 58:15, 59:31, 60:63, 61:1, 62:997, 63:255, 64:16777217, 65:8519713, 66:8650769, 67:55, 68:8912905, 69:15, 70:103, 71:13, 72:9437189, 73:45, 74:3, 75:49, 76:27, 77:29, 78:107, 79:3, 80:10485763, 81:11, 82:1, 83:1, 84:57, 85:217, 86:15, 87:27, 88:13, 89:27, 90:113, 91:223, 92:7, 93:49, 94:1, 95:15, 96:12582913, 97:1, 98:27, 99:7, 100:53, 101:115, 102:119, 103:29, 104:53, 105:237, 106:15, 107:1, 108:29, 109:1, 110:1, 111:15, 112:31, 113:29, 114:63, 115:1, 116:15, 117:249, 118:31, 119:251, 120:63, 121:1, 122:1, 123:1, 124:997, 125:251, 126:255, 127:2037, 128:16777217, 129:8454209, 130:8519713, 131:21, 132:8650769, 133:5, 134:55, 135:7, 136:8912905, 137:47, 138:15, 139:9, 140:103, 141:1, 142:13, 143:41, 144:9437189, 145:73, 146:45, 147:11, 148:3, 149:3, 150:49, 151:31, 152:27, 153:413, 154:29, 155:23, 156:107, 157:161, 158:3, 159:1, 160:10485763, 161:41, 162:11, 163:31, 164:1, 165:1, 166:1, 167:45, 168:57, 169:27, 170:217, 171:23, 172:15, 173:45, 174:27, 175:29, 176:13, 177:7, 178:27, 179:25, 180:113, 181:187, 182:223, 183:3, 184:7, 185:15, 186:49, 187:59, 188:1, 189:1, 190:15, 191:3, 192:12582913, 193:13, 194:1, 195:455, 196:27, 197:13, 198:7, 199:57, 200:53, 201:7, 202:115, 203:27, 204:119, 205:15, 206:29, 207:7, 208:53, 209:1, 210:237, 211:53, 212:15, 213:7, 214:1, 215:59, 216:29, 217:59, 218:1, 219:1, 220:1, 221:481, 222:15, 223:15, 224:31, 225:61, 226:29, 227:1, 228:63, 229:29, 230:1, 231:29, 232:15, 233:121, 234:249, 235:1, 236:31, 237:1, 238:251, 239:121, 240:63, 241:501, 242:1, 243:1, 244:1, 245:1, 246:1, 247:989, 248:997, 249:1, 250:251, 251:253, 252:255, 253:507, 254:2037, 255:1023
四舍五入的输出:1:8388609, 2:8388609, 3:8388609, 4:8388609, 5:8388609, 6:8388609, 7:7340036, 8:8388609, 9:8388609, 10:8388609, 11:5767178, 12:8388609, 13:6815751, 14:7340036, 15:7864328, 16:8388609, 17:8388609, 18:8388609, 19:4980747, 20:8388609, 21:5505025, 22:5767178, 23:6029316, 24:8388609, 25:6553602, 26:6815751, 27:7077891, 28:7340036, 29:7602181, 30:7864328, 31:8126480, 32:8388609, 33:8388609, 34:8388609, 35:4587552, 36:8388609, 37:4849688, 38:4980747, 39:5111812, 40:8388609, 41:5373953, 42:5505025, 43:5636130, 44:5767178, 45:5898246, 46:6029316, 47:6160391, 48:8388609, 49:6422530, 50:6553602, 51:6684674, 52:6815751, 53:6946819, 54:7077891, 55:7208964, 56:7340036, 57:7471109, 58:7602181, 59:7733254, 60:7864328, 61:7995403, 62:8126480, 63:8257568, 64:8388609, 65:8388609, 66:8388609, 67:4390951, 68:8388609, 69:4522008, 70:4587552, 71:4653094, 72:8388609, 73:4784130, 74:4849688, 75:4915205, 76:4980747, 77:5046294, 78:5111812, 79:5177353, 80:8388609, 81:5308417, 82:5373953, 83:5439489, 84:5505025, 85:5570561, 86:5636130, 87:5701646, 88:5767178, 89:5832710, 90:5898246, 91:5963780, 92:6029316, 93:6094852, 94:6160391, 95:6225933, 96:8388609, 97:6356994, 98:6422530, 99:6488066, 100:6553602, 101:6619138, 102:6684674, 103:6750219, 104:6815751, 105:6881283, 106:6946819, 107:7012355, 108:7077891, 109:7143427, 110:7208964, 111:7274500, 112:7340036, 113:7405572, 114:7471109, 115:7536645, 116:7602181, 117:7667718, 118:7733254, 119:7798791, 120:7864328, 121:7929865, 122:7995403, 123:8060941, 124:8126480, 125:8192021, 126:8257568, 127:8323136, 128:8388609, 129:8388609, 130:8388609, 131:4292728, 132:8388609, 133:4358217, 134:4390951, 135:4423704, 136:8388609, 137:4489235, 138:4522008, 139:4554755, 140:4587552, 141:4620296, 142:4653094, 143:4685831, 144:8388609, 145:4751362, 146:4784130, 147:4816921, 148:4849688, 149:4882455, 150:4915205, 151:4947976, 152:4980747, 153:5013530, 154:5046294, 155:5079047, 156:5111812, 157:5144580, 158:5177353, 159:5210126, 160:8388609, 161:5275649, 162:5308417, 163:5341185, 164:5373953, 165:5406721, 166:5439489, 167:5472257, 168:5505025, 169:5537793, 170:5570561, 171:5603458, 172:5636130, 173:5668884, 174:5701646, 175:5734410, 176:5767178, 177:5799944, 178:5832710, 179:5865478, 180:5898246, 181:5931019, 182:5963780, 183:5996548, 184:6029316, 185:6062084, 186:6094852, 187:6127623, 188:6160391, 189:6193162, 190:6225933, 191:6258713, 192:8388609, 193:6324226, 194:6356994, 195:6389762, 196:6422530, 197:6455298, 198:6488066, 199:6520834, 200:6553602, 201:6586370, 202:6619138, 203:6651906, 204:6684674, 205:6717495, 206:6750219, 207:6782983, 208:6815751, 209:6848515, 210:6881283, 211:6914051, 212:6946819, 213:6979587, 214:7012355, 215:7045123, 216:7077891, 217:7110659, 218:7143427, 219:7176195, 220:7208964, 221:7241732, 222:7274500, 223:7307268, 224:7340036, 225:7372804, 226:7405572, 227:7438340, 228:7471109, 229:7503877, 230:7536645, 231:7569413, 232:7602181, 233:7634950, 234:7667718, 235:7700486, 236:7733254, 237:7766023, 238:7798791, 239:7831560, 240:7864328, 241:7897097, 242:7929865, 243:7962634, 244:7995403, 245:8028172, 246:8060941, 247:8093710, 248:8126480, 249:8159250, 250:8192021, 251:8224794, 252:8257568, 253:8290347, 254:8323136, 255:8355968

最佳答案

Still, I started to wonder if adding 0.5f for rounding can be omitted for the untouched case.



使用 b==255 解决 OP 的部分问题. (OP的原始问题)

灰度转换将使用固定/恒定除法器和固定乘法器是有道理的。不要对两者使用相同的精确值,而是使用稍微不同的值。虽然这不是“同一个浮点数”,但我认为它符合 OP 的初衷。

代码可以得到预期的匹配a == a_高达 8,355,967 与 没有 + 0.5f .
float b1 = 255.0f;
float b2 = nextafterf(255.0f, 256.0f);
unsigned int a_ = (unsigned int)  ((float) a / b1 * b2);

对于 1 <= b <= 255 , 最低 a是 4,227,104 在 b == 129/

关于c - 除以和随后与相同 float 的乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47573712/

相关文章:

c 在 float 中用逗号替换点

python - 将字节转换为 float ?

python - 如何将 float 打印到 n 位小数,包括尾随 0?

c - gcc 4.6.1 (linux) 中 long double 的问题

将数字转换为整数

c++ 将 vector<pair<double,double>> 转换为 double*, double*?

c - 简单的 if/else 语句错误

c - 对上半部分和下半部分排序的数组进行排序

c - 从 Linux 内核模块共享内存以供用户空间进程访问

c - 空指针为什么我得到这个输出?