Thread overview
Float[] * Real is a Float[]?
Dec 10, 2019
Jonathan Levi
Dec 10, 2019
Adam D. Ruppe
Dec 10, 2019
Ali Çehreli
Dec 10, 2019
kinke
Dec 10, 2019
Adam D. Ruppe
Dec 11, 2019
Jab
Dec 11, 2019
Basile B.
Dec 11, 2019
kinke
December 10, 2019
Why does this not work?


    float[3] a = [10,2,4];
    real b = 5.5;
    real[3] c;
    c[] = a[]*b;

Is this intentional or a but?  Why is a[]*b a float array and not a real array?
December 10, 2019
On Tuesday, 10 December 2019 at 19:22:01 UTC, Jonathan Levi wrote:
> Why does this not work?

The [] operators work in place. It doesn't create a new array, just multiplies the existing elements.
December 10, 2019
On 12/10/19 11:26 AM, Adam D. Ruppe wrote:
> On Tuesday, 10 December 2019 at 19:22:01 UTC, Jonathan Levi wrote:
>> Why does this not work?
> 
> The [] operators work in place. It doesn't create a new array, just multiplies the existing elements.

Then the a[]*r syntax should not be allowed. We should be forced to write

 a[] *= r;

No?

Ali

December 10, 2019
On Tuesday, 10 December 2019 at 20:35:26 UTC, Ali Çehreli wrote:
> On 12/10/19 11:26 AM, Adam D. Ruppe wrote:
>> On Tuesday, 10 December 2019 at 19:22:01 UTC, Jonathan Levi wrote:
>>> Why does this not work?
>> 
>> The [] operators work in place. It doesn't create a new array, just multiplies the existing elements.
>
> Then the a[]*r syntax should not be allowed. We should be forced to write
>
>  a[] *= r;
>
> No?

No, because the statement is not correct:

void main()
{
    float[3] a = [10,2,4];
    real b = 5.5;
    float[3] c = a[] * b;
    assert(a[0] == 10); // fine, `a` is untouched
}

The actual reason can be seen by inspecting the lowered AST (-vcg-ast):

float[3] c = arrayOp(c[], a[], cast(float)b);

or alternatively, by inspecting the LLVM IR produced by LDC, or the assembly:

pure nothrow @nogc @trusted float[] core.internal.arrayop.arrayOp!(float[], float[], float, "*", "=").arrayOp(float[], float[], float)

I.e., the array-op is in single precision and the scalar rhs b is cast to a float.
December 10, 2019
On Tuesday, 10 December 2019 at 20:47:16 UTC, kinke wrote:
> No, because the statement is not correct:

oh yikes sorry about that, the static array is OK because there's already destination memory, I got stuck in my assumption about other slices where it is illegal.
December 11, 2019
On Tuesday, 10 December 2019 at 20:47:16 UTC, kinke wrote:
> On Tuesday, 10 December 2019 at 20:35:26 UTC, Ali Çehreli wrote:
>> On 12/10/19 11:26 AM, Adam D. Ruppe wrote:
>>> On Tuesday, 10 December 2019 at 19:22:01 UTC, Jonathan Levi wrote:
>>>> Why does this not work?
>>> 
>>> The [] operators work in place. It doesn't create a new array, just multiplies the existing elements.
>>
>> Then the a[]*r syntax should not be allowed. We should be forced to write
>>
>>  a[] *= r;
>>
>> No?
>
> No, because the statement is not correct:
>
> void main()
> {
>     float[3] a = [10,2,4];
>     real b = 5.5;
>     float[3] c = a[] * b;
>     assert(a[0] == 10); // fine, `a` is untouched
> }
>
> The actual reason can be seen by inspecting the lowered AST (-vcg-ast):
>
> float[3] c = arrayOp(c[], a[], cast(float)b);
>
> or alternatively, by inspecting the LLVM IR produced by LDC, or the assembly:
>
> pure nothrow @nogc @trusted float[] core.internal.arrayop.arrayOp!(float[], float[], float, "*", "=").arrayOp(float[], float[], float)
>
> I.e., the array-op is in single precision and the scalar rhs b is cast to a float.

Still doesn't really make sense. The compiler is explicitly giving those types, it seems to be a bug.

typeof(float * real) == real

That shouldn't be different for arrays, if it should be different for an array then you should have to explicitly cast the real to float.

December 11, 2019
On Wednesday, 11 December 2019 at 06:27:35 UTC, Jab wrote:
> On Tuesday, 10 December 2019 at 20:47:16 UTC, kinke wrote:
>> On Tuesday, 10 December 2019 at 20:35:26 UTC, Ali Çehreli wrote:
>>> On 12/10/19 11:26 AM, Adam D. Ruppe wrote:
>>>> On Tuesday, 10 December 2019 at 19:22:01 UTC, Jonathan Levi wrote:
>>>>> Why does this not work?
>>>> 
>>>> The [] operators work in place. It doesn't create a new array, just multiplies the existing elements.
>>>
>>> Then the a[]*r syntax should not be allowed. We should be forced to write
>>>
>>>  a[] *= r;
>>>
>>> No?
>>
>> No, because the statement is not correct:
>>
>> void main()
>> {
>>     float[3] a = [10,2,4];
>>     real b = 5.5;
>>     float[3] c = a[] * b;
>>     assert(a[0] == 10); // fine, `a` is untouched
>> }
>>
>> The actual reason can be seen by inspecting the lowered AST (-vcg-ast):
>>
>> float[3] c = arrayOp(c[], a[], cast(float)b);
>>
>> or alternatively, by inspecting the LLVM IR produced by LDC, or the assembly:
>>
>> pure nothrow @nogc @trusted float[] core.internal.arrayop.arrayOp!(float[], float[], float, "*", "=").arrayOp(float[], float[], float)
>>
>> I.e., the array-op is in single precision and the scalar rhs b is cast to a float.
>
> Still doesn't really make sense. The compiler is explicitly giving those types, it seems to be a bug.
>
> typeof(float * real) == real
>
> That shouldn't be different for arrays, if it should be different for an array then you should have to explicitly cast the real to float.

D allows implicit (and truncating) coercion from 80 bit float to 64 or 32 bits and from 80 or 64 to 32. I once made a PR proposing to disallow them but it's a disruptive change [1].
Because of that if you don't take care the D code for floating-point maths will be full of `cvtd2ss` instructions with possible precision loss.

[1]: https://issues.dlang.org/show_bug.cgi?id=17933
December 11, 2019
On Wednesday, 11 December 2019 at 06:27:35 UTC, Jab wrote:
> Still doesn't really make sense. The compiler is explicitly giving those types, it seems to be a bug.
>
> typeof(float * real) == real
>
> That shouldn't be different for arrays, if it should be different for an array then you should have to explicitly cast the real to float.

I guess that's a legitimate point. As long as the druntime array-op implementation is already prepared for such flexibility in used input and output types, the compiler could be adapted accordingly. - Mixing types probably hurts vectorizability though.