digitalmars.D - LLM's think we should have language tuples!
- Manu (30/30) Mar 24 I asked Grok to write me a portable 64x64->128 multiplication function i...
- claptrap (11/42) Mar 25 Yeah but not on how to multiply integers.
- Kagamin (2/2) Mar 25 Well, yes:
- Kagamin (2/2) Mar 26 Also LLM can be poisoned if it's given fake data:
- Walter Bright (3/5) Mar 27 Cool! Now ask it to write an 80 bit IEEE floating point multiply!
- Manu (4/10) Mar 30 I thought we had an arbitrary width float kicking around? I'm sure I've ...
- Tim (3/11) Mar 30 Do you mean this:
- Walter Bright (4/5) Mar 31 Not good enough:
- Walter Bright (2/2) Mar 27 Can also just scale up the long arithmetic asm routines that implement 3...
- Walter Bright (2/4) Mar 27 https://github.com/DigitalMars/dmc/blob/master/src/CORE16/LMATH.ASM
- ryuukk_ (61/65) Mar 27 here is what deepseek came up with:
- FeepingCreature (4/10) Mar 27 Note: to get good results from AIs, ask them to write tests as
- Manu (7/19) Mar 30 I kinda feel like every commenter in this thread rather missed the point...
- FeepingCreature (2/13) Mar 30 To be clear, we should absolutely have tuples. :)
- Alexandru Ermicioi (2/3) Mar 31 Named tuples also, like in Typescript.
- Salih Dincer (24/26) Mar 30 I think it was aware of Int128 and Claude.ai replied as follows:
- Nick Treleaven (6/10) Mar 31 Looks like Timon was working on his tuple implementation in
- Timon Gehr (24/35) Apr 01 I was working a bit on unpacking, though I think it was mostly rebasing
- Nick Treleaven (23/48) Apr 04 I built the branch and tried that sample and some variations, but
- Nick Treleaven (21/38) Apr 04 I was using `import std;`. Using single module imports (or
- user1234 (7/10) Apr 04 Why should this work ? From the type system point-of-view it's a
- user1234 (4/16) Apr 04 Sorry for the noise, i see the thing now... `AliasSeq!(int. int)`
- Nick Treleaven (14/17) Apr 04 Assigning to a tuple literal seems to be a no-op ATM:
- Nick Treleaven (7/13) Apr 04 That line lowers to:
- Timon Gehr (45/84) Apr 01 Well, it seems first they should learn how to multiply numbers (`low =
I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote: // Multiplies two 64-bit unsigned integers, returning a 128-bit result as (low, high) (ulong, ulong) mul64x64to128(ulong x, ulong y) { // Split into 32-bit halves uint x_l = cast(uint)x; uint x_h = cast(uint)(x >> 32); uint y_l = cast(uint)y; uint y_h = cast(uint)(y >> 32); // Compute partial products ulong p_ll = cast(ulong)x_l * y_l; // Bits 0-63 ulong p_lh = cast(ulong)x_l * y_h; // Bits 32-95 ulong p_hl = cast(ulong)x_h * y_l; // Bits 32-95 ulong p_hh = cast(ulong)x_h * y_h; // Bits 64-127 ulong low = p_ll; // Lower 64 bits uint p_lh_low = cast(uint)p_lh; uint p_hl_low = cast(uint)p_hl; uint p_ll_high = cast(uint)(p_ll >> 32); // Compute carry from middle terms ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high; ulong carry = sum_mid >> 32; // Upper 64 bits ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry; return (low, high); } What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :P
Mar 24
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote: // Multiplies two 64-bit unsigned integers, returning a 128-bit result as (low, high) (ulong, ulong) mul64x64to128(ulong x, ulong y) { // Split into 32-bit halves uint x_l = cast(uint)x; uint x_h = cast(uint)(x >> 32); uint y_l = cast(uint)y; uint y_h = cast(uint)(y >> 32); // Compute partial products ulong p_ll = cast(ulong)x_l * y_l; // Bits 0-63 ulong p_lh = cast(ulong)x_l * y_h; // Bits 32-95 ulong p_hl = cast(ulong)x_h * y_l; // Bits 32-95 ulong p_hh = cast(ulong)x_h * y_h; // Bits 64-127 ulong low = p_ll; // Lower 64 bits uint p_lh_low = cast(uint)p_lh; uint p_hl_low = cast(uint)p_hl; uint p_ll_high = cast(uint)(p_ll >> 32); // Compute carry from middle terms ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high; ulong carry = sum_mid >> 32; // Upper 64 bits ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry; return (low, high); } What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PYeah but not on how to multiply integers. It never adds the low 32 bits of "sum_mid", to the upper 32 bits of "low", plus it would also need to check if that overflowed. something like... ulong tmp = low + (sum_mid << 32); bool carry_from_low = (tmp < low); //** low = tmp; then later: if (carry_from_low) high++; **: if the result of the addition is lower than the initial value then it overflowed
Mar 25
Well, yes: https://forum.dlang.org/post/nydunscuwdcinamqails forum.dlang.org
Mar 25
Also LLM can be poisoned if it's given fake data: https://blog.cloudflare.com/ai-labyrinth/
Mar 26
On 3/24/2025 9:44 PM, Manu wrote:I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote:Cool! Now ask it to write an 80 bit IEEE floating point multiply! (So we can cross compile from Arm to X86!)
Mar 27
On Fri, 28 Mar 2025 at 02:16, Walter Bright via Digitalmars-d < digitalmars-d puremagic.com> wrote:On 3/24/2025 9:44 PM, Manu wrote:I thought we had an arbitrary width float kicking around? I'm sure I've got one floating about somewhere...I asked Grok to write me a portable 64x64->128 multiplication functionin D toget the pattern, and this is what it wrote:Cool! Now ask it to write an 80 bit IEEE floating point multiply! (So we can cross compile from Arm to X86!)
Mar 30
On Sunday, 30 March 2025 at 09:25:56 UTC, Manu wrote:On Fri, 28 Mar 2025 at 02:16, Walter Bright via Digitalmars-d < digitalmars-d puremagic.com> wrote:Do you mean this: https://dlang.org/library/std/numeric/custom_float.htmlCool! Now ask it to write an 80 bit IEEE floating point multiply! (So we can cross compile from Arm to X86!)I thought we had an arbitrary width float kicking around? I'm sure I've got one floating about somewhere...
Mar 30
On 3/30/2025 4:04 AM, Tim wrote:Do you mean this: https://dlang.org/library/std/numeric/custom_float.htmlNot good enough: "These formats are for storage only; all operations on them are performed by first implicitly extracting them to real first."
Mar 31
Can also just scale up the long arithmetic asm routines that implement 32 bit arithmetic on the 16 bit x86.
Mar 27
On 3/27/2025 9:15 AM, Walter Bright wrote:Can also just scale up the long arithmetic asm routines that implement 32 bit arithmetic on the 16 bit x86.https://github.com/DigitalMars/dmc/blob/master/src/CORE16/LMATH.ASM
Mar 27
On Thursday, 27 March 2025 at 17:31:54 UTC, Walter Bright wrote:On 3/27/2025 9:15 AM, Walter Bright wrote:here is what deepseek came up with: To convert the provided x86 assembly code for 32-bit arithmetic operations to AARCH64, we leverage ARM's efficient instruction set for multiplication, division, and comparison. Here's the equivalent implementation: ``` .section .text .align 2 .global _LMUL _LMUL : // Unsigned 32-bit multiply, result 64-bit in x0 umull x0, w0, w1 ret .global _ULDIV _ULDIV : // Check for division by zero beq div0_unsigned // Perform unsigned division udiv w2, w0, w1 // Quotient in w2 msub w3, w2, w1, w0 // Remainder in w3 mov w0, w2 // Return quotient mov w1, w3 // Return remainder ret div0_unsigned: // Handle division by zero: return (0xFFFFFFFF, 0) ret .global _LDIV _LDIV : // Check for division by zero beq div0_signed // Perform signed division sdiv w2, w0, w1 // Quotient in w2 msub w3, w2, w1, w0 // Remainder in w3 mov w0, w2 // Return quotient mov w1, w3 // Return remainder ret div0_signed: // Handle division by zero: return (-1, 0) ret .global _LCMP _LCMP : // Compare two signed 32-bit values cmp w0, w1 b.gt .greater b.lt .less ret .greater: ret .less: ret ```Can also just scale up the long arithmetic asm routines that implement 32 bit arithmetic on the 16 bit x86.https://github.com/DigitalMars/dmc/blob/master/src/CORE16/LMATH.ASM
Mar 27
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote: What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PNote: to get good results from AIs, ask them to write tests as well, then run the tests and post the answers and ask them to debug the issue. :) You have to handhold a bit.
Mar 27
On Fri, 28 Mar 2025 at 06:35, FeepingCreature via Digitalmars-d < digitalmars-d puremagic.com> wrote:On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:I kinda feel like every commenter in this thread rather missed the point ;) I know how to multiply big numbers; I was just throwing random stuff at it trying to test its limits. The operation is not what I was interested in here; I just liked that it assumed we had tuples! It's right to do so as far as I'm concerned, and it's embarrassing that we don't.I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote: What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PNote: to get good results from AIs, ask them to write tests as well, then run the tests and post the answers and ask them to debug the issue. :) You have to handhold a bit.
Mar 30
On Sunday, 30 March 2025 at 09:33:26 UTC, Manu wrote:On Fri, 28 Mar 2025 at 06:35, FeepingCreature via Digitalmars-dTo be clear, we should absolutely have tuples. :)Note: to get good results from AIs, ask them to write tests as well, then run the tests and post the answers and ask them to debug the issue. :) You have to handhold a bit.I kinda feel like every commenter in this thread rather missed the point ;) I know how to multiply big numbers; I was just throwing random stuff at it trying to test its limits. The operation is not what I was interested in here; I just liked that it assumed we had tuples! It's right to do so as far as I'm concerned, and it's embarrassing that we don't.
Mar 30
On Monday, 31 March 2025 at 05:50:13 UTC, FeepingCreature wrote:To be clear, we should absolutely have tuples. :)Named tuples also, like in Typescript.
Mar 31
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote:I think it was aware of Int128 and Claude.ai replied as follows: ```d import std.int128; auto mul64x64to128(ulong x, ulong y) { uint x_low = cast(uint)x; uint x_high = cast(uint)(x >> 32); uint y_low = cast(uint)y; uint y_high = cast(uint)(y >> 32); ulong mul_ll = cast(ulong)x_low * y_low; ulong mul_lh = cast(ulong)x_low * y_high; ulong mul_hl = cast(ulong)x_high * y_low; ulong mul_hh = cast(ulong)x_high * y_high; ulong low = mul_ll; ulong high = mul_hh + (mul_hl >> 32) + (mul_lh >> 32); ulong mid = (mul_ll >> 32) + (mul_hl & 0xFFFFFFFF) + (mul_lh & 0xFFFFFFFF); low += (mid & 0xFFFFFFFF) << 32; high += mid >> 32; return Int128(high, low); } ``` SDB 79
Mar 30
On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PLooks like Timon was working on his tuple implementation in February: https://github.com/tgehr/dmd/commits/tuple-syntax/ Also: https://dconf.org/2023/slides/gehr.pdf#page=109
Mar 31
On 3/31/25 22:37, Nick Treleaven wrote:On Tuesday, 25 March 2025 at 04:44:15 UTC, Manu wrote:I was working a bit on unpacking, though I think it was mostly rebasing to master after that had undergone refactorings. It is more or less ready (and OpenD already pulled the current state), but there are various small things to finish. E.g.: - expanding a zero-element tuple does not work properly yet (in general, even unrelated to unpacking) https://github.com/dlang/dmd/issues/20842 I though I would have time to maybe fix this, but got sidetracked last time I attempted to see it through. - Unpacking does not yet support auto-expanding, for example: (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3); does not work yet. - I need to write an extensive test suite and address anything it may catch. - I have to write the DIP and suffer through the bikeshedding on the forum. Of course, one way to continue would be to just write tests for what works and pull this (e.g., behind a -preview switch) and to allow anyone who can spend the time required to take over the polishing effort. In general, I still fully intend to finish this, but I don't know when I will manage to get it over the finish line at the level of quality I think is perfect. It has already taken way too long, mostly because I have not been able to focus on this for any significant amount of time beside my day job and various other obligations.What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PLooks like Timon was working on his tuple implementation in February: https://github.com/tgehr/dmd/commits/tuple-syntax/ Also: https://dconf.org/2023/slides/gehr.pdf#page=109
Apr 01
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:It is more or less ready (and OpenD already pulled the current state), but there are various small things to finish.Good to hear.E.g.: - expanding a zero-element tuple does not work properly yet (in general, even unrelated to unpacking) https://github.com/dlang/dmd/issues/20842 I though I would have time to maybe fix this, but got sidetracked last time I attempted to see it through. - Unpacking does not yet support auto-expanding, for example: (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3); does not work yet.I built the branch and tried that sample and some variations, but they each get: ``` /home/nick/git/dmd/generated/linux/release/64/../../../../../pho os/std/json.d(144): Error: no property `Entry` for type `object.TypeInfo_AssociativeArray` JSONValue[string] unordered; ^ /home/nick/git/dmd/generated/linux/release/64/../../../../druntime/im ort/object.d(1289): class `TypeInfo_AssociativeArray` defined here class TypeInfo_AssociativeArray : TypeInfo ^ ``` And: ``` core.exception.AssertError src/dmd/typinf.d(112): Assertion failure ``` I'm not sure if it's something to do with my setup or not. My Phobos is recent git, probably that's why.- I need to write an extensive test suite and address anything it may catch. - I have to write the DIP and suffer through the bikeshedding on the forum. Of course, one way to continue would be to just write tests for what works and pull this (e.g., behind a -preview switch) and to allow anyone who can spend the time required to take over the polishing effort.A `-preview` switch would be great. Then with the tests devs will at least keep it up-to-date with master. I think people would be more likely to work on it too, or at least file bugs.In general, I still fully intend to finish this, but I don't know when I will manage to get it over the finish line at the level of quality I think is perfect. It has already taken way too long, mostly because I have not been able to focus on this for any significant amount of time beside my day job and various other obligations.Thanks for your work on this!
Apr 04
On Friday, 4 April 2025 at 12:25:03 UTC, Nick Treleaven wrote:I built the branch and tried that sample and some variations, but they each get: ``` /home/nick/git/dmd/generated/linux/release/64/../../../../../pho os/std/json.d(144): Error: no property `Entry` for type `object.TypeInfo_AssociativeArray` JSONValue[string] unordered; ^ /home/nick/git/dmd/generated/linux/release/64/../../../../druntime/im ort/object.d(1289): class `TypeInfo_AssociativeArray` defined here class TypeInfo_AssociativeArray : TypeInfo ^ ``` And: ``` core.exception.AssertError src/dmd/typinf.d(112): Assertion failure ``` I'm not sure if it's something to do with my setup or not. My Phobos is recent git, probably that's why.I was using `import std;`. Using single module imports (or avoiding std) works! ```d auto (x, y, z) = (1, 2, 3); void main() { import core.stdc.stdio; printf("%d %d %d\n", x,y,z); //import std.stdio; //writeln(x,y,z); } ``` Uncommenting writeln causes a link error for me though: ``` Error: undefined reference to `pure nothrow bool core.internal.gc.blockmeta.__setArrayAllocLengthImpl(ref core.memory.BlkInfo_, ulong, bool, ulong, ulong)` referenced from `pure nothrow bool core.internal.array.utils.__setArrayAllocLength!(char).__set rrayAllocLength(ref core.memory.BlkInfo_, ulong, bool, ulong)` ```
Apr 04
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:- Unpacking does not yet support auto-expanding, for example: (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3); does not work yet.Why should this work ? From the type system point-of-view it's a bit like if you say that ```d ((int,int), int) a = (1,2,3); ``` has to work. You dont have to support that.
Apr 04
On Friday, 4 April 2025 at 13:43:36 UTC, user1234 wrote:On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:Sorry for the noise, i see the thing now... `AliasSeq!(int. int)` __is not a tuple__, it's supposed to expand to two disctint VarDecls within the parent tuple.- Unpacking does not yet support auto-expanding, for example: (AliasSeq!(int. int) x, int y) = tuple(1, 2, 3); does not work yet.Why should this work ? From the type system point-of-view it's a bit like if you say that ```d ((int,int), int) a = (1,2,3); ``` has to work. You dont have to support that.
Apr 04
On Tuesday, 1 April 2025 at 19:26:53 UTC, Timon Gehr wrote:- expanding a zero-element tuple does not work properly yet (in general, even unrelated to unpacking) https://github.com/dlang/dmd/issues/20842Assigning to a tuple literal seems to be a no-op ATM: ```d void main() { int a,b; (a, b) = (4, 5); printf("%d %d\n", a,b); // 0 0 auto t = (6, 7); printf("%d %d\n", t[0], t[1]); // 6 7 (a, b) = t; printf("%d %d\n", a,b); // 0 0 still } ```
Apr 04
On Friday, 4 April 2025 at 13:59:52 UTC, Nick Treleaven wrote:Assigning to a tuple literal seems to be a no-op ATM: ```d void main() { int a,b; (a, b) = (4, 5);That line lowers to: ```d tuple(a, b).opAssign(tuple(4, 5)); ``` So it's assigning to a temporary tuple copy of a and b's data, rather than the fields by reference.
Apr 04
On 3/25/25 05:44, Manu wrote:I asked Grok to write me a portable 64x64->128 multiplication function in D to get the pattern, and this is what it wrote: // Multiplies two 64-bit unsigned integers, returning a 128-bit result as (low, high) (ulong, ulong) mul64x64to128(ulong x, ulong y) { // Split into 32-bit halves uint x_l = cast(uint)x; uint x_h = cast(uint)(x >> 32); uint y_l = cast(uint)y; uint y_h = cast(uint)(y >> 32); // Compute partial products ulong p_ll = cast(ulong)x_l * y_l; // Bits 0-63 ulong p_lh = cast(ulong)x_l * y_h; // Bits 32-95 ulong p_hl = cast(ulong)x_h * y_l; // Bits 32-95 ulong p_hh = cast(ulong)x_h * y_h; // Bits 64-127 ulong low = p_ll; // Lower 64 bits uint p_lh_low = cast(uint)p_lh; uint p_hl_low = cast(uint)p_hl; uint p_ll_high = cast(uint)(p_ll >> 32); // Compute carry from middle terms ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high; ulong carry = sum_mid >> 32; // Upper 64 bits ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry; return (low, high); } What I loved is that its function returned a pair of ulong's, because apparently it made an assumption that we had in-language tuples! I wonder where it got that idea? We should learn from our AI overlords! :PWell, it seems first they should learn how to multiply numbers (`low = p_ll` is wrong of course): ``` import std; // Multiplies two 64-bit unsigned integers, returning a 128-bit result as (low, high) (ulong, ulong) mul64x64to128(ulong x, ulong y) { // Split into 32-bit halves uint x_l = cast(uint)x; uint x_h = cast(uint)(x >> 32); uint y_l = cast(uint)y; uint y_h = cast(uint)(y >> 32); // Compute partial products ulong p_ll = cast(ulong)x_l * y_l; // Bits 0-63 ulong p_lh = cast(ulong)x_l * y_h; // Bits 32-95 ulong p_hl = cast(ulong)x_h * y_l; // Bits 32-95 ulong p_hh = cast(ulong)x_h * y_h; // Bits 64-127 ulong low = p_ll; // Lower 64 bits uint p_lh_low = cast(uint)p_lh; uint p_hl_low = cast(uint)p_hl; uint p_ll_high = cast(uint)(p_ll >> 32); // Compute carry from middle terms ulong sum_mid = cast(ulong)p_lh_low + p_hl_low + p_ll_high; ulong carry = sum_mid >> 32; // Upper 64 bits ulong high = p_hh + (p_lh >> 32) + (p_hl >> 32) + carry; return (low, high); } void main(){ auto (low, high) = mul64x64to128(101010101010101010, 101010101010101010); assert((BigInt(high)<<64)+BigInt(low) == BigInt(101010101010101010)^^2); } ``` ``` $ ./dmd -run test_grok_tuple.d core.exception.AssertError test_grok_tuple.d(34): Assertion failure ---------------- ??:? _d_assertp [0x62dc8b38d148] ??:? _Dmain [0x62dc8b382d9c] ``` (With my freshly rebased DMD fork at: https://github.com/tgehr/dmd/tree/52c336591aac0a2023a715ba92e95efc8da0f9ad )
Apr 01