数组索引在C中,它必须是整数吗?它可以是浮点吗?
正如标题所示。。。我需要使用浮点作为数组索引,但是GCC编译器抛出了一个错误 基本上我有一个数学函数,比如F(x,t),其中函数有变量x和t。我遇到的问题是,我试图在float类型中增加x和t,这样我就可以在不同的x和t下为函数计算不同的值。所以我自然会有两个for循环:数组索引在C中,它必须是整数吗?它可以是浮点吗?,c,arrays,floating-point,integer,C,Arrays,Floating Point,Integer,正如标题所示。。。我需要使用浮点作为数组索引,但是GCC编译器抛出了一个错误 基本上我有一个数学函数,比如F(x,t),其中函数有变量x和t。我遇到的问题是,我试图在float类型中增加x和t,这样我就可以在不同的x和t下为函数计算不同的值。所以我自然会有两个for循环: for (x = x_min; x < x_max; x += dx) { for (t = t_min; t < t_min; t += dt) { f[x][t] = 10*x + 10
for (x = x_min; x < x_max; x += dx) {
for (t = t_min; t < t_min; t += dt) {
f[x][t] = 10*x + 10*t; // Over simplified.. but you get the idea
}
}
// And then perform some fourier transform
fft(f[x][t], 256, 1);
for(x=x_最小值;x
是的,这就是为什么我想知道是否有可能将浮点作为数组索引。C中的数组索引必须是整数是的,它必须是整数,因为您基本上是在执行指针算术,其中
&array[0]
是指向数组开头的指针(从技术上讲,它必须是一个整数,因为这是规范所说的,但这就是原因)
在这种情况下,从基指针向上移动一个对象大小的一小部分是没有意义的。您几乎可以保证不会指向元素的开头
这样看:
int array[10] = { 0 };
// analagous to *(array + 5), where '5' is
// offsetting the pointer by sizeof(int) * 5 bytes
// If you were able to add 5.5 to the base address
// the value assigned to 'i' below would be interpreted as
// the four bytes following *(array + 5.5), i.e., garbage data.
int i = array[5];
首先,我觉得这是一个奇怪的问题,也许您可以给我们更多关于您实际试图实现的目标的信息,而不是您提出的解决方案?在这种情况下,我们可能会给您提供更有用的答案。如果您只是将整数存储在浮点变量中、强制转换或其他转换将值插入整数类型应该可以正常工作。例如:
array[(int)x] = y;
如果您真的想用非整数索引对数组进行索引,您必须为自己设计一个更高级别的数据结构,并且它可能不会是一个时间效率属性意义上的“数组”。是。根据C99标准§6.5.2.1(数组订阅): 其中一个表达式的类型为“指向对象类型的指针”,另一个表达式的类型为整数,结果的类型为“类型”
如果要将浮点数用作数组索引,则需要将其强制转换为整数。这通常是一个坏主意,因为计算过程中的任何微小舍入错误都可能很容易导致截断后数组索引被关闭1。根据您真正想做的事情,您可能可以使用缩放索引浮动作为“索引”的偏移版本:
#定义数组大小100
条目数组[arraySize];
float scaleFactor=10;
浮动底座=0.1;
浮动值=0.3;
//这种截断就是我们有多对一映射的地方。
索引=(int)((值-基)*scaleFactor);
如果(索引>=0&&index
正如您所发现的,数组索引必须是整数类型。为了达到您想要的效果,您可以通过浮点增量缩放和偏移整数索引:
double x, t;
int x_i, t_i;
for (x_i = 0; x_i < NX; x_i ++) {
x = x_min + x_i * dx;
for (t_i = 0; t_i < NT, t_i++) {
t = t_min + t_i * dt;
f[x_i][t_i] = 10*x + 10*t;
}
}
双x,t;
int x_i,t_i;
对于(x_i=0;x_i
是的,我们可以,但每存储一个字节需要64KB的内存
浮点数存储在4字节=32位中,
您可以使用整数指针“读取”它。不是将/cast/round转换为整数,而是“读取”原始字节。
在c代码中:
float f = 3.1415;
int *ip = NULL;
ip = (int *)&f;
printf("f = %f\ni = %i = 0x%x\n", f, *ip, *ip);
// f = 3.141500
// i = 1078529622 = 0x40490e56
// ^^^^
// bfloat16
要将所有浮点用作数组索引,
我们需要2**32字节=4千兆字节的内存
为了减少内存使用,我们可以使用bfloat16
类型这只是一个“截断”版本(有损压缩) 在32位浮点中,
只有7位尾数:
bfloat16 = SEEEEEEE EMMMMMMM
float32 = SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
bfloat16
以“机器学习”大肆宣传,
但也用于传感器数据。一些奇特的处理器对bfloat16有硬件支持 float32和bfloat16之间的转换非常简单,
仅因字节顺序不同而复杂(endianness)
bfloat16.c
// convert between float32 and bfloat16
// use float as array index --> see end of file
// public domain + no warranty
#include <stdint.h> // uint16_t, int8_t
#include <stdlib.h> // malloc, free, size_t
#include <string.h> // memset
#include <stdbool.h> // bool
#include <stdio.h> // printf
typedef uint16_t bfloat16; // --> "maybe remove"
typedef float float32;
// stolen from tensorflow bfloat16.cc
void float32_to_bfloat16_be(float32 *src, bfloat16 *dst, size_t size)
{
uint16_t *s = (uint16_t *)src;
uint16_t *d = (uint16_t *)dst; // maybe remove
for (; size != 0; s += 2, d++, size--) {
// big endian byte order
*d = s[0];
}
}
void float32_to_bfloat16_le(float32 *src, bfloat16 *dst, size_t size)
{
uint16_t *s = (uint16_t *)src;
uint16_t *d = (uint16_t *)dst; // maybe remove
for (; size != 0; s += 2, d++, size--) {
// little endian byte order
*d = s[1];
}
}
void bfloat16_to_float32_be(bfloat16* src, float32* dst, size_t size)
{
uint16_t *s = (uint16_t *)src; // maybe remove
uint16_t *d = (uint16_t *)dst;
for (; size != 0; s++, d += 2, size--) {
// big endian byte order
d[0] = *s;
d[1] = 0;
}
}
void bfloat16_to_float32_le(bfloat16* src, float32* dst, size_t size)
{
uint16_t *s = (uint16_t *)src; // maybe remove
uint16_t *d = (uint16_t *)dst;
for (; size != 0; s++, d += 2, size--) {
// little endian byte order
d[0] = 0;
d[1] = *s;
}
}
// detect byte order at runtime
// http://esr.ibiblio.org/?p=5095#comment-415728
// this usually does not generate any code at all with GCC even with -O1
// ignore byte orders other than LE and BE
static inline bool is_big_endian() {
const uint16_t endianness = 256; // 0b 00000001 00000000
return *(const uint8_t *)&endianness;
}
// demo program
int main()
{
// function pointers for the current byte order
void (*float32_to_bfloat16)(float32*, bfloat16*, size_t) = NULL;
void (*bfloat16_to_float32)(bfloat16*, float32*, size_t) = NULL;
// detect byte order at runtime
if (is_big_endian())
{
printf("byte order is big endian\n");
float32_to_bfloat16 = &float32_to_bfloat16_be;
bfloat16_to_float32 = &bfloat16_to_float32_be;
}
else
{
printf("byte order is little endian\n");
float32_to_bfloat16 = &float32_to_bfloat16_le;
bfloat16_to_float32 = &bfloat16_to_float32_le;
}
// convert one number
float32 a1 = 3.1415;
bfloat16 b1 = 0;
float32_to_bfloat16(&a1, &b1, 1);
bfloat16 a2 = 0x4049;
float32 b2 = 0;
bfloat16_to_float32(&a2, &b2, 1);
printf("%1.4f --> 0x%04x\n", a1, b1);
printf("%1.4f <-- 0x%04x\n", b2, a2);
// convert many numbers
float32 a3[2] = {2.7182, 1.4142};
bfloat16 b3[2] = {0};
float32_to_bfloat16(a3, b3, 2);
bfloat16 a4[2] = {0x402d, 0x3fb5};
float32 b4[2] = {0};
bfloat16_to_float32(a4, b4, 2);
printf("%1.4f --> 0x%04x\n", a3[0], b3[0]);
printf("%1.4f <-- 0x%04x\n", b4[0], a4[0]);
printf("%1.4f --> 0x%04x\n", a3[1], b3[1]);
printf("%1.4f <-- 0x%04x\n", b4[1], a4[1]);
// array with float index [half-float index]
int8_t *n_fi = NULL; // int8_t = -128 .... +127
// init array
n_fi = malloc(0xffff * sizeof(typeof(*n_fi)));
memset(n_fi, 0, 0xffff * sizeof(typeof(*n_fi)));
// 0xffff = 2**16-1 = 65535 = 64Ki-1
// key
float32 k = 3.1415;
// convert key
bfloat16 k16 = 0;
float32_to_bfloat16(&k, &k16, 1);
// value
int8_t v = 123;
// write
n_fi[k16] = v;
// read
printf("n_fi[0x%04x] = %i\n", k16, n_fi[k16]);
// read next = zero from array init
printf("n_fi[0x%04x] = %i\n", k16+1, n_fi[k16+1]);
// close array
free(n_fi);
}
//在float32和bfloat16之间转换
//将浮点用作数组索引-->请参见文件末尾
//公共领域+无担保
#包括//uint16\u t、int8\u t
#包括//malloc、免费、大小\u t
#include//memset
#包括//bool
#包括//printf
typedef uint16\u t bfloat16;//-->“可能删除”
typedef float float32;
//从tensorflow bfloat16.cc中被盗
无效浮动32至浮动16(浮动32*src,浮动16*dst,大小)
{
uint16_t*s=(uint16_t*)src;
uint16_t*d=(uint16_t*)dst;//可能会删除
对于(;size!=0;s+=2,d++,size--){
//大端字节顺序
*d=s[0];
}
}
无效浮动32至浮动16(浮动32*src,浮动16*dst,大小)
{
uint16_t*s=(uint16_t*)src;
uint16_t*d=(uint16_t*)dst;//可能会删除
对于(;size!=0;s+=2,d++,size--){
//小端字节顺序
*d=s[1];
}
}
无效bfloat16到bfloat16*src、FLOAT16*dst、大小
{
uint16_t*s=(uint16_t*)src;//可能会删除
uint16_t*d=(uint16_t*)dst;
对于(;size!=0;s++,d++=2,size--){
//大端字节顺序
d[0]=*s;
d[1]=0;
}
}
无效浮点数16至浮点数32(浮点数16*src,浮点数32*dst,大小)
{
uint16_t*s=(uint16_t*)src;//可能会删除
uint16_t*d=(uint16_t*)dst;
对于(;size!=0;s++,d++=2,size--){
//小端字节顺序
d[0]=0;
d[1]=*s;
}
}
//在运行时检测字节顺序
// http://esr.ibiblio.org/?p=5095#comment-415728
//这通常不会使用GCC生成任何代码,即使使用-O1也是如此
//忽略除LE和BE以外的字节顺序
静态内联bool是_big_endian(){
常数16_t endianness=256;//0b 0000000 1 00000000
返回*(const uint8\u t*)&
// convert between float32 and bfloat16
// use float as array index --> see end of file
// public domain + no warranty
#include <stdint.h> // uint16_t, int8_t
#include <stdlib.h> // malloc, free, size_t
#include <string.h> // memset
#include <stdbool.h> // bool
#include <stdio.h> // printf
typedef uint16_t bfloat16; // --> "maybe remove"
typedef float float32;
// stolen from tensorflow bfloat16.cc
void float32_to_bfloat16_be(float32 *src, bfloat16 *dst, size_t size)
{
uint16_t *s = (uint16_t *)src;
uint16_t *d = (uint16_t *)dst; // maybe remove
for (; size != 0; s += 2, d++, size--) {
// big endian byte order
*d = s[0];
}
}
void float32_to_bfloat16_le(float32 *src, bfloat16 *dst, size_t size)
{
uint16_t *s = (uint16_t *)src;
uint16_t *d = (uint16_t *)dst; // maybe remove
for (; size != 0; s += 2, d++, size--) {
// little endian byte order
*d = s[1];
}
}
void bfloat16_to_float32_be(bfloat16* src, float32* dst, size_t size)
{
uint16_t *s = (uint16_t *)src; // maybe remove
uint16_t *d = (uint16_t *)dst;
for (; size != 0; s++, d += 2, size--) {
// big endian byte order
d[0] = *s;
d[1] = 0;
}
}
void bfloat16_to_float32_le(bfloat16* src, float32* dst, size_t size)
{
uint16_t *s = (uint16_t *)src; // maybe remove
uint16_t *d = (uint16_t *)dst;
for (; size != 0; s++, d += 2, size--) {
// little endian byte order
d[0] = 0;
d[1] = *s;
}
}
// detect byte order at runtime
// http://esr.ibiblio.org/?p=5095#comment-415728
// this usually does not generate any code at all with GCC even with -O1
// ignore byte orders other than LE and BE
static inline bool is_big_endian() {
const uint16_t endianness = 256; // 0b 00000001 00000000
return *(const uint8_t *)&endianness;
}
// demo program
int main()
{
// function pointers for the current byte order
void (*float32_to_bfloat16)(float32*, bfloat16*, size_t) = NULL;
void (*bfloat16_to_float32)(bfloat16*, float32*, size_t) = NULL;
// detect byte order at runtime
if (is_big_endian())
{
printf("byte order is big endian\n");
float32_to_bfloat16 = &float32_to_bfloat16_be;
bfloat16_to_float32 = &bfloat16_to_float32_be;
}
else
{
printf("byte order is little endian\n");
float32_to_bfloat16 = &float32_to_bfloat16_le;
bfloat16_to_float32 = &bfloat16_to_float32_le;
}
// convert one number
float32 a1 = 3.1415;
bfloat16 b1 = 0;
float32_to_bfloat16(&a1, &b1, 1);
bfloat16 a2 = 0x4049;
float32 b2 = 0;
bfloat16_to_float32(&a2, &b2, 1);
printf("%1.4f --> 0x%04x\n", a1, b1);
printf("%1.4f <-- 0x%04x\n", b2, a2);
// convert many numbers
float32 a3[2] = {2.7182, 1.4142};
bfloat16 b3[2] = {0};
float32_to_bfloat16(a3, b3, 2);
bfloat16 a4[2] = {0x402d, 0x3fb5};
float32 b4[2] = {0};
bfloat16_to_float32(a4, b4, 2);
printf("%1.4f --> 0x%04x\n", a3[0], b3[0]);
printf("%1.4f <-- 0x%04x\n", b4[0], a4[0]);
printf("%1.4f --> 0x%04x\n", a3[1], b3[1]);
printf("%1.4f <-- 0x%04x\n", b4[1], a4[1]);
// array with float index [half-float index]
int8_t *n_fi = NULL; // int8_t = -128 .... +127
// init array
n_fi = malloc(0xffff * sizeof(typeof(*n_fi)));
memset(n_fi, 0, 0xffff * sizeof(typeof(*n_fi)));
// 0xffff = 2**16-1 = 65535 = 64Ki-1
// key
float32 k = 3.1415;
// convert key
bfloat16 k16 = 0;
float32_to_bfloat16(&k, &k16, 1);
// value
int8_t v = 123;
// write
n_fi[k16] = v;
// read
printf("n_fi[0x%04x] = %i\n", k16, n_fi[k16]);
// read next = zero from array init
printf("n_fi[0x%04x] = %i\n", k16+1, n_fi[k16+1]);
// close array
free(n_fi);
}