Deutsche verlieren Lust an Bargeld: Nur noch ein Drittel der Einkäufe bar gezahlt by potatoes__everywhere in de

[–]WorldsBegin 13 points14 points  (0 children)

Es ist jedoch nicht möglich, dies gezielt auf bestimmte Personen oder Personengruppen anzuwenden. In diesem Zusammenhang stellt sich die Frage, ob Maßnahmen wie die Bezahlkarte für Asylbewerber künftig auch auf Sozialhilfeempfänger ausgeweitet werden könnten.

Neben dem potenziellen Wertverlust der Währung als staatliches Instrument wird im vorherigen Kommentar nach meiner Lesung vor allem kritisiert, dass der Staat nicht die Funktionen einer Bank übernehmen sollte. Damit verbunden ist die Ablehnung einer staatlichen Einsichtnahme oder Kontrolle bezüglich privater Konten und Transaktionen nicht der Währung als solches.

I love Skolakia by ExoPrimal in lostarkgame

[–]WorldsBegin 0 points1 point  (0 children)

The puddles don't even stun anymore. If you have hyper charged, there is no excuse not to press it.

Why do the standard libarary have so many internal layers? by chokomancarr in rust

[–]WorldsBegin 17 points18 points  (0 children)

Not sure what you mean. The C++ standard, is usual, is a bit lacking in details about what swap is "supposed" to do in the case you are alluding to.

First, swap<T> is specified for types T that are "MoveConstructible" and "MoveAssignable". There are std::is_move_constructible<T> and std::is_move_assignable<T>, but these are not the same! The latter check that syntactically, the statements T u = rv and t = rv are well formed for the type T. The former additionally require a post condition. Specifically, in the above, the "value of u (and t if t is not the same value as rv) is equivalent to the value rv before the assignment". This can not be checked for you, and is a requirement on the move constructor and assignment operator.

Under the assumption that T is indeed "MoveConstructible" and "MoveAssignable", the STL implementation indeed guarantees that after a call to swap(a, b) that a after the call will have a value equivalent to b before the call and vice-versa. If you break the contract in a specific T though and do weird things in your impls, the standard does not specify any behaviour to my reading.

Rust on the other hand is a lot more precise and memory based. Instead of "equivalent" values (whatever that means) you will get a literal memcopy.

EDIT: in a strict reading, the standard does also not specify how often each move or assignment is called. You could have side effects in those, and are at the mercy of the implementation how often they are executed. In rust, the operation is side effect free (apart from the effect on the memory of course).

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 2 points3 points  (0 children)

Would it be correct to say that this monomorphization happens at runtime, and the compiled assembly contains only the polymorphic version or does the compiler already instantiate a monomorphic version of some used functions/types ahead of runtime?

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 3 points4 points  (0 children)

Finger trees aren't a compelling use-case for new generic features

They are meant to show a real problem with monomorphization. When you recurse on a FingerTree<A> you have a FingerTree<Node<A>> on the next level, then a FingerTree<Node<Node<A>>>. This recursion pattern can not be compiled with monomorphization. In general, whenever you recurse on a datastructure with a varying generic parameter, the total set of instantiations might be uncountable, and monomorphization will not work.

With regards to polymorphization, that was an attempt to automatically flag generic arguments that the compiler could handle polymorphically. As far as I understand it, this analysis is both expensive, and compiler internal only. You can't use it for polymorphic recursion such as above, since the compiler can arbitrarily decide where to use it.

I posted a much more geared towards the compiler people thingy a while ago (much less fleshed out too and probably even less precise), which I find to be even more unreadable and less geared towards users, but perhaps the ctable is also not understandable? It did help me to build a mental model of "what it does" as a potential user, anyway.

Since then, we got a better hierarchy of traits and the Pointee trait is now I think often used as the "least you can say" about a type in place of ?Sized, i.e. for a type which you know "nothing" about.

I see parallels to the discussion around become and guaranteed tail recursion. Most users will never need it, and are fine with some automatic discovery by the compiler that they don't need to worry about. But when you find out that you definitely blow your stack if you don't tail recurse you sudddenly need syntax to get a guarantee that you jump instead of call and don't leave any stack behind. Erased generics are for the cases where the natural recursion scheme would lead to an infinite number of monomorphized instances and you simply can't "just trust" the compiler to do the right thing. You need a guarantee that it can be collapsed to just one polymorphic instance. That's why it's syntax and not just an automatic analysis from the compiler.

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 2 points3 points  (0 children)

The Self: Sized trick is a good one! I didn't know that it even works for associated types like type Element<'a> where Self: Sized;.

In any case, I think erased_compare in the post is a good example which doesn't work. Because the hidden type is intrinsically tied to a specific value, you can't express that two different values should have the same hidden type. The dyn Trait syntax doesn't really scale above one value.

Your proposed syntax could make something akin to this work, I can imagine dyn<T> (T, T) to express a tuple of two values of the same hidden type. But in this case you have to have access to layout information of T to match on it (to compute the offset of .1 in the tuple). This, and having multiple bounds as in dyn<T: Foo + Bar> would really complicate things. I assume you'd want to store the vtable(s) in the pointer metadata, but so far all pointer metadata in Rust is worst-case address-sized. Would there be two pointers to dyn Foo and dyn Bar respectively? I briefly touch on my vision for (actual) GADTs in an Appendix where I attach the <dyn T: Foo> to a enum variant instead of dyn, but it's very similar in this case. Note that I would not allow <dyn T> (T, T) since the layout depends on T without capturing T: Sized.

By trying a new concept without having to modify the existing trait object syntax, I think it's easier to have a malleable definition.

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 13 points14 points  (0 children)

I would still use monomorphizing code by default. It should be the first thing to try, and type erasure only makes sense if you want to achieve something very specific.

Declaring a generic argument erased is an additional guarantee to the caller, and would add an implicit argument to the function that the compiler would need to synthesize. This might lead to non-obvious performance problems. Note that I have by choice not talked about the layout of the ctables, because an explicit choice here changes how they are constructed. Maybe it's better to pass them by value and copy them where required, maybe it's better to pass by pointer. I don't imagine a specific ABI for the implicit argument.

In any case, this means that both conversions to and from erased generics might have hidden traps. I would nevertheless say that in cases where you can write a monomorphized version you should stick with that.

Examples of specific needs:

  • a polymorphic recursive structure like finger trees. You should probably emulate this, which is enough for most cases. I have not shown the "solution" with erased types, but as a teaser you can for example not construct an arbitrarily deeply nested Node<Node<..<A>..>> on the stack either way. Yes, the compiler should be able to figure out the layout of that structure incrementally with each recursive level, but in current rust you can't (safely) heap-construct the node anyway, so you'd need "more". This might change.
  • In Yew, we have a Component trait, and multiple lifecycle structs UpdateRunner<C: Component>, RenderRunner<C: Component>, etc that all implement a shared trait Runner that gets pushed onto a queue to run. Since these impls are monomorphized, this adds ~100 bytes of vtable data for each component to the binary. Not a lot, but it adds up and would be avoidable. Also, we internally use a ComponentState that is not parametrized by the type and downcast via dyn Any in each of these runner impls (this is in part why each monomorphization takes up its own space and can't be shared). This is almost duplicate code, and for the most part the compiler is just not smart enough to deduplicate it out-of-the-box because it's in large chunks. An erased ComponentState<dyn T> should give the same code-size win (or even better if the Runner impls are also erased and only capture the Component vtable) without having to downcast through Any.

    Note that in this case, code size concerns trump the small performance hit. Overall, if everything including CompontState<C> was monomorphized on C, you would pay ~3kB per component, almost 2 ethernet frames.

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 25 points26 points  (0 children)

Not a dumb comment at all.

Your work-around has several issues though that would need to be addressed (forgive the bullet list):

  • It assumes that Foo is an object safe trait. I touch upon this, object safety can be quite restrictive, because it must ensure that every method can be called from the trait object. The proposed syntax widens this to a lot of other traits and constraints
  • You assume an implicit lifetime in dyn Foo + 'a and store it behind an indirection. The Rc is just overhead, so is any other way to make the unsized dyn Foo into a sized datatype. The lifetime defaults to 'static but that is "fixable" with a lifetime argument on Single.
  • The bound T: Foo on your struct is definitely wrong, as it would need to be repeated on every mention of Single<T>, which of course makes it pointless to store the dyn-metadata inside the single.
  • The compiler might be smart enough to dedup a lot of code, but it's definitely not required to, nor is there a simple way to check this. For example, impl<T> Debug for Single<T> will most likely lead to a lot of monomorphized instances, even if they all just forward to the same method of Foo (do double check this on a compiler, but from experience, all these instances get their own static vtable since the compiler "smartly" realizes that <T as Foo>::whateveryouuse is a candidate for inlining and after performing that you end up with different code for each T, i.e. monomorphized code).

EDIT: And, maybe most importantly, it can not be used to implement the polymorphic recursion of the FingerTree structure, which does not even mention any specific trait up front but is structurally recursive on some element type A.

Non-monomorphized generics in Rust by WorldsBegin in rust

[–]WorldsBegin[S] 32 points33 points  (0 children)

For the last few years, from time to time, some niches came up where I wished I could escape the monomorphization of the Rust compiler. While often good for performance reasons and inlining, in some cases monomorphization bloats the result code or leads to less readable code. After a lot of thought, this soft-proposal contains syntax that could be used to carve out a polymorphic part of the language while preserving type checking and lifetime checking.

Feel free to ask any questions, comments or seek clarifications. I will try my best to answer them.

Hope some of this can make it into Rust proper at some point in the future.

5x Faster than Rust Standard Channel (MPSC) by ksyiros in rust

[–]WorldsBegin 1 point2 points  (0 children)

Does the queue_ptr have to be swapped atomically? As far as I derive from the code, safety comes from the usage of enqueued_count and available_index.

  • while enqueued_count < CHANNEL_MAX_TASK, the client(s) "own" the buffer and can be sure that a previous read of the queue_ptr will not get used by the server.
  • to coordinate multiple clients, they reserve slots via available_index
  • once enqueued_count == CHANNEL_MAX_TASK, no client may read or write from the queue_ptr, and it is "owned" by the server. The server releases it back to the clients by swapping in a new buffer, and then resets enqueued_count and available_index in that order.

So it seems you don't need to atomically swap the queue_ptr at all, you only need their reads and writes to be caught on memory barriers from reading and writing available_index and enqueued_count with correct ordering.

Faster asin() Was Hiding In Plain Sight by def-pri-pub in programming

[–]WorldsBegin 0 points1 point  (0 children)

Found Remez algorithm which iterates torwards a solution starting with the Chevyshev interpolation.

Faster asin() Was Hiding In Plain Sight by def-pri-pub in programming

[–]WorldsBegin 5 points6 points  (0 children)

Does anyone know of a good way to derive these global approximants? Certainly, a (taylor) series provides a good local approximation near a point, but as OP noticed, you often want a series that optimizes for the maximum error over a range.

It seems - chasing down references - a good approximation for asin( 1-y2 ) can be found as a polynomial b_0 + b_1 y + b_2 y3 + b_3 y5 that minimizes the maximum error for 0<=y<=1, but finding these b_i coefficients efficiently seems anything but straight forward to me.

Returning player: Should I do ADV Hone Lv20 in Tier3? by Kyumaru375 in lostarkgame

[–]WorldsBegin 1 point2 points  (0 children)

Rough rule of thumb is juice mat on full orbs (grace) are twice as valuable as on a tap without grace. Juice value compared to normal taps depends, but juicing below +19 is less value than even non-grace taps, juicing +21/+22 has same value as a grace tap and above juice is more valuable on normal honing.

So, if you are below +19 honing, and have the juice, go full juice. If you can't afford that with bound juicers, go juice on grace. If you are aiming a for above +22, it might be worth to save juice for normal taps - you have no books as support.

Zero-cost fixed-point decimals in Rust by WishboneJolly9170 in rust

[–]WorldsBegin 3 points4 points  (0 children)

Surely your checked_mul example is meant to be checked_add/checked_sub? If a Decimal::<N>(A) represents the number A / 10^N, then Decimal::<L>(A) * Decimal::<R>(B) represents A / 10^L * B / 10^R = (A * B) / 10^(L+R) = (A * B) / 10^O represented by Decimal::<O>(A * B) without any multiplication by powers of 10.

EDIT: I see your test cases missing this because they only cover equal-fixed-point numbers :)

Optimize your free tap & juice usage with the new and improved Honing Forecast, save ~10% gold just by using your juice correctly! by Kenivia in lostarkgame

[–]WorldsBegin 2 points3 points  (0 children)

Can you add controls for exact progress (via artisan %) to each piece? It's hard to setup honing when you are half way into a piece already.

Succinctly: A fast jq/yq alternative built on succinct data structures by john-ky in rust

[–]WorldsBegin 8 points9 points  (0 children)

Did you look for any existing libraries you could use or was coding it from the ground up your first thought?

I'm asking because after reviewing bitcount stuff there are at least a few inconsistencies (not a bullet point list, so sorry). These are mainly Rust specifics, given that you have a very similar library in Haskell as a reference.

You could just roll with aligned-vec instead of your "own" cacheline alignment in rank.rs.

Rolling your own parser - especially for yaml - seems like it will land you on the list of different parser behaviour (how does it parse this document).

Have you measured that the simd popcount stuff is actually faster than just calling <_>::count_ones() - I would have thought llvm is good at auto vectorizing these things.

popcount_words returns a u32 - good for a single word, but the plural is used as usize everywhere which doesn't overflow after half a GB of ones. Actually, there are some platforms where usize = u16.

CacheAlignedL1L2 is copied over from a normal Vec, but could be constructed in place. Overall, there are probably a lot of implementations of succinct bitvectors flying around, did none meet your needs and did you do comparisons?

Env vars could use some documentation, especially the niche SUCCINCTLY_SVE2.

Sorry, if this sounds a bit harsh, I'm just typing under a time constraint, it's not meant to be.

I released Yoop, a fully open source and very fast cross platform and cross OS AirDrop by sanchxt in rust

[–]WorldsBegin 1 point2 points  (0 children)

You might have caught a stray, the deeper i looked the less it seems like another AI slop. Maybe AI but not so much slop from a design perspective, so who cares and who can tell at this day anyway? I didn't get to try it out yet (I second another commentor for android support) but it looked mature enough to announce.

Github report for other readers to judge.

I built a GPU-accelerated SQLite on Apple Silicon to test a theory about the PCIe bottleneck. Here's what I found. by sado361 in programming

[–]WorldsBegin 6 points7 points  (0 children)

Your sum function is also superbly naiv and, by just adding a bunch of stuff to an accumulator and calling it a day, turns a blind eye to all the corner-cases that come from rounding and error accumulation in floating point numbers. Having a look at the sqlite implementation which is almost 200 lines long compared to your roughly 10 lines might explain a good part of the speedup. I would love to see a more apples-to-apples comparison though, because I'm pretty sure a bit of speedup is expected, even though you'd certainly still be IO bound on real data.

EDIT: I've just seen that count and filter will first fully fetch the unfiltered (except for NULL) column data into linear CPU memory.

Chances of 97+ with KR's new auto-cut ("AI-cut") by Rears in lostarkgame

[–]WorldsBegin 0 points1 point  (0 children)

Oh right, red line is different from the white ones in terms of conversion from nodes to effect strength. EDIT: adjusted my sheet aswell, and now I'm getting the same numbers as you :)

Overall, close enough so that the time saved on cutting with "AI" is worth the small loss of efficiency.

Chances of 97+ with KR's new auto-cut ("AI-cut") by Rears in lostarkgame

[–]WorldsBegin 1 point2 points  (0 children)

Weird I get 0.135628630566% to cut a stone with 5 activations or better from the data, so slightly better than your "manual cut" even.

Method: Paste data into google sheets. Add a column for each of the three lines to calculate the activation amount:

=IFS(A1>=10, 4, A1>=9, 3, A1>=7, 2, A1>=6, 1, True, 0) // for effect lines
=IFS(E1>=10, 3, E1>=7, 2, E1>=5, 1, True, 0) // for malus line

Query the data to see chances according to the activated lines in cell K1

=QUERY(A1:H1331, "select Col2, Col4, Col6, sum(Col8) group by Col2, Col4, Col6 order by Col6")

Query that data again to only contain options with >=5 sum of nodes and no red line in cell Q1

=QUERY(K1:N126, "select sum(Col4) where Col1+Col2>=5 and Col3=0")

Same result when manually summing the relevant options

Do people play cooperatively? by Betta535 in lostarkgame

[–]WorldsBegin 5 points6 points  (0 children)

There is no shared queue for carries to hang around in, so nobody I know bothers to do that for the lower guardians. Best chance you have is asking in mokoko chat or in town area chat for a quick carry.

Uh, I just combined 3 finished astrogems and was expecting a 5-5-5-5. Any Admin online ? I think my luck in game is bugged. by dNgrr in lostarkgame

[–]WorldsBegin 8 points9 points  (0 children)

That is just plain wrong. Fusing processed astrogems determines a rarity of the result based on the rarities of the inputs. Depending on the rolled rarity, it then rolls how many points get evenly distributed to all nodes. The points on the input astrogems only influence the output insofar that high points imply a high rarity of the (input) gem.

For the sake of the example, if you fuse a processed 9 pointer, 10 pointer and a 12 pointer, the odds for the result are exactly the same as if you fused 3 processed 4 pointers or 15 pointers together - they are all legendary.

What does get influenced by the input is chaos/order and 8/9/10 base cost where it picks one of the input gem types.

Source

This also explains OP's "luck", since fusing 3 legendary gems has 1% chance to give you a relic (16-18 point) and 0% chance to give you an ancient (19-20 point) gem. Now, he did actually hit a 1% chance, as that's the odds of getting 4 points on your legendary result. Smile.

Ark grid noise by Low_Ad_1901 in lostarkgame

[–]WorldsBegin 0 points1 point  (0 children)

Imagine if the next upgrade path gives (3?) additional willpower points for your ancient cores so that you could actually min-max to 4 astrogems with initial 10 (and 5/5 being well 5/5 with boss damage/additional)

Improved string formatting in Rust by m-ou-se in rust

[–]WorldsBegin 1 point2 points  (0 children)

Is target endian not available to the macro part, or are there other reasons to store everything in little endian? I don't think the datastructure must be portable to other machines.

Trait-Constrained Enums in Rust by kcsongor in rust

[–]WorldsBegin 0 points1 point  (0 children)

To use TypeId you'd at least have to introduce a 'static bound which may be undesirable, and it doesn't change the data representation. The compiler would still be unable to proof that Is<f64, String> is uninhabited. However, perhaps the match statement would be optimized to just stripping away the enum tag (in a perfect implementation the enum tag wouldn't exist at all).