From dennisk at netspace.net.au Wed Aug 12 11:54:20 2020 From: dennisk at netspace.net.au (Dennis Katsonis) Date: Wed, 12 Aug 2020 21:54:20 +1000 Subject: [phobos] std.numeric returns incorrect results for integer types. Message-ID: <5070362e-9810-a6bf-9a4d-7a60b00efaf3@netspace.net.au> 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; }