[phobos] std.numeric returns incorrect results for integer types.

Dennis Katsonis dennisk at netspace.net.au
Wed Aug 12 11:54:20 UTC 2020


std.numeric is listed in the documentation as "Floating point numerics
functions.".

I have noted that the noramlize function for std.numeric will accept an
integer type, and report a dud result.


ulong[] arr = [540,640,44];
normalize!(typeof(arr))(arr,256);  \\ arr = [0, 0, 0]

One would expect either an error, or a valid result here.  I think this
is a design flaw, as the function happy returns 0 without complaint.
This would lead to incorrect behaviour for someone who missed the scant
mention that its for floats.

I think that there should be either a template constraint to reject
integral types, or that it should handle integral types correctly.

I have found the below version handles integer types correctly, *IF*
that is the path you want to take.  I can make a pull request if necessary.


bool normalize(R)(R range, ElementType!(R) sum = 1)
if (isForwardRange!(R))
{
    ElementType!(R) s = 0;
    // Step 1: Compute sum and length of the range
    static if (hasLength!(R))
    {
        const length = range.length;
        foreach (e; range)
        {
            s += e;
        }
    }
    else
    {
        uint length = 0;
        foreach (e; range)
        {
            s += e;
            ++length;
        }
    }
    // Step 2: perform normalization
    if (s == 0)
    {
        if (length)
        {
	  immutable f = sum / range.length;
	  foreach (ref e; range) e = f;
        }
        return false;
    }
    // The path most traveled
    assert(s >= 0);
    static if (isIntegral!(ElementType!(R))) {
      immutable f = sum / s.to!real;
      foreach (ref e; range)
	e = round(e*f).to!(ElementType!(R));
    } else {
      immutable f = sum / s;
      foreach (ref e; range)
	e *= f;
    }

    return true;
}


More information about the phobos mailing list