优化:提前计算出每个区间的斜率和截距。查找到后,只需要做一次乘法和加法
#include "stdio.h"
#include "stdint.h"
/***************************************************************
* @Copyright(C) 2020-2021,
* @FileName: 线性插值
* @Author: kane
* @Version: 0.1.1
* @LastDate: 2021.8.14
************************************************************/
#ifndef _LINEAR_INTERP_H_
#define _LINEAR_INTERP_H_
#include <stdint.h>
struct LinearInterp
{
// 初始化曲线
void (*Init)(struct LinearInterp *self, float *arr_x, float *arr_y, float *arr_k, float *arr_b, uint32_t size);
// 调用计算
float (*Cal)(struct LinearInterp *self, float val);
float out;
struct
{
float *arr_x; //x0,x1,x2
float *arr_y; //y0,y1,y2
float *s_k; //斜率
float *s_b; //截距
int32_t size; //点的数量
} pvt;
};
void LinearInterp_Create(struct LinearInterp *self);
#endif
/***************************************************************
* @Copyright(C) 2020-2021,
* @FileName: 线性插值
* @Author: kane
* @Version: 0.1.1
* @LastDate: 2021.8.14
************************************************************/
#include "linear_Interp.h"
#include "string.h"
#include <stdlib.h>
//初始化函数,动态绑定x,y,k,b,size,并计算k,b
static void _Init(struct LinearInterp *self, float *arr_x, float *arr_y, float *arr_k, float *arr_b, uint32_t size)
{
self->pvt.arr_x = arr_x;
self->pvt.arr_y = arr_y;
self->pvt.s_k = arr_k;
self->pvt.s_b = arr_b;
self->pvt.size = size;
for (uint32_t i = 0; i < (size - 1); ++i)
{
self->pvt.s_k[i] = (float)(self->pvt.arr_y[i] - self->pvt.arr_y[i + 1]) / (self->pvt.arr_x[i] - self->pvt.arr_x[i + 1]);
self->pvt.s_b[i] = (float)(self->pvt.arr_y[i] - self->pvt.s_k[i] * self->pvt.arr_x[i]);
}
}
//插值计算
static float _Cal(struct LinearInterp *self, float val)
{
int32_t left = 0, mid = 0;
int32_t right = self->pvt.size - 1;
float x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
// 二分法
while (left <= right)
{
mid = (left + right) / 2;
if (val < self->pvt.arr_x[mid])
right = mid - 1;
else if (self->pvt.arr_x[mid] < val)
left = mid + 1;
else
break;
}
// 头尾检测
if (mid == (self->pvt.size - 1))
{
mid = mid - 1;
}
else if (mid == 0)
{
mid = 0;
}
else
{
mid = (self->pvt.arr_x[mid] <= val) ? mid : mid - 1; // 中间二分查找出现的情况
}
// 3.Linear interpolation 方法1
/*x0 = self->pvt.arr_x[mid];
y0 = self->pvt.arr_y[mid];
x1 = self->pvt.arr_x[mid + 1];
y1 = self->pvt.arr_y[mid + 1];
self->out = y0 + (((y1 - y0) * (val - x0)) / (x1 - x0));
printf("out1 = %f\n", self->out);*/
//方法2
printf("out2 = %f\n", (self->pvt.s_k[mid] * val) + (self->pvt.s_b[mid]));
self->out = (self->pvt.s_k[mid] * val) + (self->pvt.s_b[mid]);
return self->out;
}
//创建一个插值句柄,动态绑定函数
void LinearInterp_Create(struct LinearInterp *self)
{
memset(self, 0, sizeof(struct LinearInterp));
self->Init = _Init;
self->Cal = _Cal;
}
// //demo
// int main(void)
// {
// LinearInterp line_interp = {0};
// float arr_x[5] = {1, 5, 8, 13, 17};
// float arr_y[5] = {4, 45, 10, 40, 20};
// float arr_k[sizeof(arr_x) / sizeof(arr_x[0]) - 1] = {0}; //这个自动计算填充 斜率
// float arr_b[sizeof(arr_x) / sizeof(arr_x[0]) - 1] = {0}; //这个自动计算填充 截距
// LinearInterp_Create(&line_interp);
// line_interp.Init(&line_interp, arr_x, arr_y, arr_k, arr_b, 5);
// float res = line_interp.Cal(&line_interp, 2);
// return 0;
// }