Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy: Check if float array contains whole numbers

In Python, it is possible to check if a float contains an integer value using n.is_integer(), based on this QA: How to check if a float value is a whole number.

Does numpy have a similar operation that can be applied to arrays? Something that would allow the following:

>>> x = np.array([1.0 2.1 3.0 3.9])
>>> mask = np.is_integer(x)
>>> mask
array([True, False, True, False], dtype=bool)

It is possible to do something like

>>> mask = (x == np.floor(x))

or

>>> mask = (x == np.round(x))

but they involve calling extra methods and creating a bunch of temp arrays that could be potentially avoided.

Does numpy have a vectorized function that checks for fractional parts of floats in a way similar to Python's float.is_integer?

like image 996
Mad Physicist Avatar asked Jan 27 '16 15:01

Mad Physicist


People also ask

How do I quickly check if all elements of NumPy array are floats?

How do I quickly check if all elements of numpy array are floats? I need to write a function F which takes a numpy array with dtype=object, and returns whether all elements of an array are floats, integers, or strings. For example:

How to check if an array is numeric in NumPy?

import numpy as np def is_numeric_array(array): """Checks if the dtype of the array is numeric. Booleans, unsigned integer, signed integer, floats and complex are considered numeric. Parameters ---------- array : `numpy.ndarray`-like The array to check.

How to check if a float is a whole number in Python?

Python Check if Float is a Whole Number The easiest way to check if a number is a whole number in Python is using the Python float is_integer() function. Skip to primary navigation Skip to main content Skip to primary sidebar

How to use the ‘ in ‘ operator in NumPy?

For this purpose, we use the “ in ” operator. “ in ” operator is used to check whether certain element and values are present in a given sequence and hence return Boolean values ‘ True ” and “ False “. In the above example, we check whether values 2, 0, 6, 50, 10 are present in Numpy array ‘ n_array ‘ using the ‘ in ‘ operator.


2 Answers

From what I can tell, there is no such function that returns a boolean array indicating whether floats have a fractional part or not. The closest I can find is np.modf which returns the fractional and integer parts, but that creates two float arrays (at least temporarily), so it might not be best memory-wise.

If you're happy working in place, you can try something like:

>>> np.mod(x, 1, out=x)
>>> mask = (x == 0)

This should save memory versus using round or floor (where you have to keep x around), but of course you lose the original x.

The other option is to ask for it to be implemented in Numpy, or implement it yourself.

like image 180
hunse Avatar answered Nov 12 '22 16:11

hunse


While the accepted method of (x % 1) == 0 is quite adequate, it bothers me that there is no way to accomplish this natively in numpy, especially given the existence of float.is_integer in vanilla python.

I therefore did a bit of research on the floating point formats supported by numpy (float16, float32, float64, float128 (acutally extended precision)), and on how to write a ufunc.

The result is that for IEEE754 floats small enough to fit into a corresponding unsigned integer type (pretty much everything up to float64 on a normal machine), you can do the checks with some simple bit twiddling. For example, here is a C99 function that very quickly tells you if your float32 contains an integer value:

#include <stdint.h>

int is_integer(float n)
{
    uint32_t k = ((union { float n; uint32_t k; }){n}).k;

    // Zero when everything except sign bit is zero
    if((k & 0x7FFFFFFF) == 0) return 1;

    uint32_t exponent = k & 0x7F800000;

    // NaN or Inf when the exponent bits are all ones
    // Guaranteed fraction when exponent < 0
    if(exponent == 0x7F800000 || exponent < 0x3F800000) return 0;
    // Guaranteed integer when exponent >= FLT_MANT_DIG - 1
    if(exponent >= 0x4B000000) return 1;
    // Otherwise, check that the significand bits past the exponent are zeros
    return (k & (0x7FFFFF >> ((exponent >> 23) - 0x7F))) == 0;
}

I went ahead and wrapped this function and its siblings in a ufunc, which can be found here: https://github.com/madphysicist/is_integer_ufunc. One nice feature is that this ufunc returns True for all integer types instead of raising an error. Another is that it runs anywhere from 5x to 40x faster than (x % 1) == 0, depending on dtype and input size.

Based on the linked tutorial, you can install with python setup.py {build_ext --inplace, build, install}, depending on how bad you want it. Perhaps I should see if the numpy community is interested in including this ufunc.

like image 23
Mad Physicist Avatar answered Nov 12 '22 15:11

Mad Physicist