0

I have a function that is passed an array of coordinates in 1D. These are the ends of sections for which piecewise functions have been defined in a dictionary, and also passed in as input. However, when making comparisons, the array values change precision in the loop, and so the comparison is not working anymore. Here is the code:

def parse_mass_data(mass_prop_file, slices, wingline, y_coords):
    data = pd.read_csv(mass_prop_file, delim_whitespace=True,index_col=False, skiprows = 10, skipfooter=(slices+5))
    cogy = []
    mass = []
    y = y_coords.astype(np.float64)
    print(y)
    for i in range(len(data['Name'].values)):
        if data['Name'][i] != 'Totals'and data['Name'][i] != 'Name':
            cogy.append(data['cgY'].values[i])
            mass.append(data['Mass'].values[i])

    cogy = np.array(list(map(float,cogy)))
    mass = np.array(list(map(float,mass)))
    x = np.zeros(len(mass))
    z = np.zeros(len(mass))

    for i in range(len(mass)):
        for j in range(len(y_coords)-1):
            if cogy[i] >= y[j] and cogy[i] < y[j+1]:
                x[i] = wingline['xy'][j][0] * cogy[i] + wingline['xy'][j][1]
                z[i] = wingline['yz'][j][0] * cogy[i] + wingline['yz'][j][1]
            # print(wingline['xy'][j],wingline['yz'][j])
            print(y[j],y[j+1])
        # print(i,x[i],cogy[i],z[i])

The output is as follows:

[ 0.  6. 10.]
0.0 5.999999999999999
5.999999999999999 9.999999999999998
0.0 5.999999999999999
5.999999999999999 9.999999999999998
0.0 5.999999999999999
5.999999999999999 9.999999999999998
0.0 5.999999999999999
5.999999999999999 9.999999999999998

As you can see, the input array, and the values from the loop index don't match, preventing the comparisons from working. How can I make this comparison, or there a better way of implementing this?

I understand that numpy has an interpolate function here, but I already have the equations to fit the values to, and if the input data is not good to begin with, can I use that function?

hpaulj
  • 221,503
  • 14
  • 230
  • 353
keg504
  • 23
  • 5
  • 5
    They do match, just to numerical precision. That's what happens when you work with floating point numbers. – jared Jul 31 '23 at 14:39
  • 1
    See [link](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) on the issues arising from storing decimal float values in binary. **isclose** functions are available for comparisons. – user19077881 Jul 31 '23 at 15:06
  • You have a couple of pandas dataframes, `data` and `wingline`. What's the dtypes? If column dtype is already float, you shouldn't need that `map(float, ...)` stuff. '>=' kinds of comparisons on floats are not reliable. If you can work with integers this would be better. – hpaulj Jul 31 '23 at 15:59
  • @jared so the numpy representation of 6. is not an integer? – keg504 Jul 31 '23 at 17:19
  • 1
    @keg504 Not when you explicitly convert it to `np.float64` type, no – chrslg Jul 31 '23 at 17:38
  • Thanks for your comments, I've solved the problem based on the link @user19077881 provided, and posted the answer below. I'm not sure if it meets the standards for an answer. – keg504 Aug 01 '23 at 14:24

1 Answers1

0

Due to how computers work, this is a known problem according to the this similar question: Is floating point math broken?

My solution was to use absolute value comparisons, as suggested in the accepted answer to that question. Here is the edited code:

mass = np.array(list(map(float,mass)))
x = np.zeros(len(mass))
z = np.zeros(len(mass))

for i in range(len(mass)):
    for j in range(len(y_coords)-1):
        if cogy[i] >= 0:
            if abs(cogy[i] - y_coords[j] > 0.0001) and abs(cogy[i] - y_coords[j+1] <= 0.0001):
                x[i] = wingline['xy'][j][0] * cogy[i] + wingline['xy'][j][1]
                z[i] = wingline['yz'][j][0] * cogy[i] + wingline['yz'][j][1]
        else:
            if abs(cogy[i]) - abs(y_coords[j]) >= 0.0001 and abs(cogy[i]) - abs(y_coords[j+1]) < 0.0001:
                x[i] = -wingline['xy'][j][0] * cogy[i] + wingline['xy'][j][1]
                z[i] = -wingline['yz'][j][0] * cogy[i] + wingline['yz'][j][1]
keg504
  • 23
  • 5
  • 1
    Hi, you understand the problem and suggest a reasonable solution. I would suggest you take a look at np.allclose/np.isclose which are builtin functions to address the exact problem the OP is facing. – kubatucka Aug 04 '23 at 15:14
  • Thanks, I wasn't aware of that function, I'll use that next time! – keg504 Aug 04 '23 at 19:16