Arithmetic conversion leads to unexpected results for linspace/logspace

Issue #336 resolved
Tim Zimmermann created an issue

Hi,

I came across an unexpected result with the freshly introduced generator expressions. Consider the following piece of code:

#include <blaze/math/DynamicVector.h>
#include <iostream>

int main(void) {
    size_t N = 10;
    int start = -10;
    int end = -1;
    auto x = blaze::linspace(N, start, end);
    blaze::DynamicVector<int> y = x;
    std::cout << x << std::endl;
    std::cout << y << std::endl;
    return 0;
}

Compiling (tested with gcc 9.2.0 and clang 9.0.1) and executing yields:

$ ./a.out
( 18446744073709551606 )
( 18446744073709551607 )
( 18446744073709551608 )
( 18446744073709551609 )
( 18446744073709551610 )
( 18446744073709551611 )
( 18446744073709551612 )
( 18446744073709551613 )
( 18446744073709551614 )
( 18446744073709551615 )

(         -10 )
(          -9 )
(          -8 )
(          -7 )
(          -6 )
(          -5 )
(          -4 )
(          -3 )
(          -2 )
(          -1 )

The result indicates that although I am explicitly using a signed integer type the element type of the returned expression is in fact unsigned and therefore suffers from mod 2 arithmetic. Interestingly, constructing a new vector (y in the example above) recovers the result I was expecting in the first place.

I digged a little deeper into this issue and found that line 660 in \math\expressions\DVecGenExpr.h causes the issue:

...
return generate<TF>( size, [ start=std::move(start), delta=std::move(end) ]( size_t index ) {
      return evaluate( start + index*delta );
      //                            ^
      //                            |
      // conversion to unsigned int according to "Usual arithmetic conversions" point 4 on
      // https://en.cppreference.com/w/c/language/conversion
   } ); 
...

The problem also persist for logspace of course. A quick fix that made it work for my purposes was to introduce a index type IT as

using IT = If_t<IsInteger_v<BT> && std::is_signed_v<BT>, std::make_signed_t<size_t>, size_t>;

and then let the lambda passed to generate take IT instead of size_t. That said I only considered ints, and have not thought about any possible edge cases.

Thanks,

Tim

Comments (7)

  1. Klaus Iglberger

    Hi Tim!

    Thanks a lot for pointing out this defect. You are correct, there are some edge cases that are not handled properly yet. I apologize for the inconveniences and will try to fix the issue as quickly as possible. Thanks again,

    Best regards,

    Klaus!

  2. Klaus Iglberger

    Commit ee64f71 fixes the linspace() and logspace() functions for dense vectors. The fix is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.8.

  3. Log in to comment