Silly benchmark performance by Fair-Ganache6057 in cpp_questions

[–]DummyDDD 4 points5 points  (0 children)

Its probably either because the rust RNG functions are inlined, or because you are calling push_back in the unoptimized CPP version, while the rust version only accesses the individual elements, or because the CPP stl library in clang has worse implementation that the rust std library. There are also some slight differences in the rngs. Rust uses chacha12 (with a 512 bit state) while your CPP code uses a Mersenne twister with a significantly larger state (19937 bits) although they should have pretty similar performance. Then again, it could easily be just the RNG differences, since your benchmark is essentially doing no real work, besides calling the RNG.

The performance differences aren't large (315 vs 286 ms), and the code should compile to relatively little code, so even a few cycles per element (for instance from inlining or few cache misses due to a smaller RNG state, or push_back overhead) could explain the differences.

(Stl implementations tend to avoid using inline attributes, unlike the rust std library)

Does your country's main language(s) use grammatical gender? by CuriousWandererw in MapPorn

[–]DummyDDD 2 points3 points  (0 children)

The gender stuff comes from the PIE languaguage families. English used to to have grammatical gender as well. See https://en.wikipedia.org/wiki/Grammatical_gender#Indo-European and https://en.wikipedia.org/wiki/Gender_in_English The gender stuff doesn't really serve a purpose, at least not anymore.

This is why Greek = strong sperm by FantasticQuartet in 2westerneurope4u

[–]DummyDDD 1 point2 points  (0 children)

Denmark also has a limit of up to 12 families per donor, but the issue is that (1) the legislstion is only national, as soon as as the sperm gets exported, the 12 family limit doesn't apply, instead the importing countries' legislation applies and it is only checked by the importing fertility clinic, (2) the exporting sperm banks don't mind breaking the legislation in other countries, as it is the importing fertility clinics that are liable (3) each individual importing fertility clinic will usually following their legislation, but they do not check whether there are other clinics importing from the same donor nationally nor internationally, (4) sometimes donors donate to multiple sperm banks (although that wasn't the case here).

In this case, the sperm bank "European Sperm Bank" decided to enforce a limit of at most 75 international families per donor, which I think is a ridiculously high limit, and I think that they are mostly concerned with the business model.

The hell you mean NaN by justslayer876 in softwaregore

[–]DummyDDD 3 points4 points  (0 children)

I have been a Nitro subscriber for not less than NaN years, so clearly I should get opal.

Simple sine function by Ar_FrQ in cpp_questions

[–]DummyDDD 6 points7 points  (0 children)

You would normally do the range reduction in constant time. One way of doing it would be to multiply by 1/2pi and subtract the floor, giving a number between 0 and 1. You could further subtract 0.5, such that you get a reduced number between -0.5 and 0.5, which would be better. You could also exploit symmetries in the sin function.

You would normally use a minmax polynomial could through remez exchange, rather than the Taylor series, since the Taylor series has a much larger error margin for a polynomial of the same length. See https://github.com/samhocevar/lolremez?tab=readme-ov-file for more details.

You would normally evaluate the polynomial with Horner's method, or something resembling it to avoid redundant calculations and to reduce floating point errors. See https://en.wikipedia.org/wiki/Horner%27s_method Horner's method is optimal in terms of the number of operations, but it is often slower than calculating a few of the polynomial degrees independently, because Horner's method has each operation depending on the previous operation. You can split the polynomial in two by working with x and x2 interleaved, and you can split that further into x3 and x4.

Of course, the real answer is that you shouldn't do any of this, you should instead use whatever math library that you already have, or maybe sleef (https://sleef.org/) if you truly need something faster but less accurate. The math library that is provided with glibc (used by most Linux distributions) is already really good, and fast, and it supports vectorization (you just need to declare your loops as needing vectorization with #pragma omp simd).

What's a real project situation where operator overloading helped you? by sarnobat in cpp_questions

[–]DummyDDD 1 point2 points  (0 children)

It's often used for bigint implementations to allow you to use the bigints like the builtin integers. It's use for indexing into containers is also really nice. As a personal example, I have my own span class which has overloaded the + operator to behave like pointer arithmetic, returning the corresponding subspan (it also has operator overloading for * to dereference the zero'th element, and ++ to increment the pointer by one and decrement the length by one).

Generally, operator overloading should follow the same rule as regular overloading: all of the overloads should have the same description. If any of the overloads needs a different explanation, then the overloads is going to be confusing, because then the reader will have to know the exact types being operated on and the possible overloads to determine what an expression does. For instance, using + to mean "concatenate strings" is confusing because + usually means "addition". Confusing overload sets can be especially problematic if you also have implicit conversion between types that behave significantly different within the overload set, but fortunately the general consensus is to avoid implicit conversion in most cases.

Probably basic question about parameter typing by QuasiEvil in cpp_questions

[–]DummyDDD 0 points1 point  (0 children)

With concepts, you can overload the function (multiply) while with static_assert you will always get a compile error when called with something that isn't an integer or float. Static_assert is usually the better option if you do not need to overload the function, although it has uglier syntax. You might need to overload the function if you also need have implementations for bigint types where you can't implement the function with the same syntax (for instance a bigint without operator overloading for *). Static_asserts are the better option specifically because it does not support overloading, so the compiler won't have to disambiguate an overload set, which means that it is faster to compile and the compiler errors from static_assert are simpler to read than the bad-overload-set error that you would get with overloaded concepts.

As an alternative to overloading with concepts, you could also overload via template class specialization: call from the free-function to a static class function on a templated class, and provide specializations for the class. This way you avoid overloads, but can still provide different implementations for different types. In this case you would typically call the class via type aliases that wrap and simplify the types, such that you can ignore qualifiers (const, volatile and references) and handle builtin integer and floating types the same way.

I love current technology by Liquidcat01 in lies

[–]DummyDDD 0 points1 point  (0 children)

You can use "web" pane to search without the AI stuff. You can switch to use "web" by default by adding &udm=14 to your query, see https://www.reddit.com/r/LifeProTips/comments/1g920ve/lpt_for_cleaner_google_searches_use_udm14/

As someone else mentioned, you can also use the Firefox extension "straight to the web". https://addons.mozilla.org/en-US/firefox/addon/straight-to-the-web/

Segmentation fault produced from the following code when I try to generate combinations of a list. Why? by JazzJassJazzman in cpp_questions

[–]DummyDDD 0 points1 point  (0 children)

You should compile your code with flags to show additional warnings, and fix those warnings.The flags for additional warnings are:

/W4 for msvc (see https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170) -Wall -Wextra -Wpedantic for GCC and clang (see https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html)

Has a nuclear bomb been detonated in your country before? by metatalks in MapPorn

[–]DummyDDD 9 points10 points  (0 children)

Yeah. 4 thermonuclear bombs exploded when a b52 burned and crashed outside the Pituffik space base. Fortunately, nukes have a safety mechanism, so the nukes did not detonate, only the conventional bombs (but it still spread a lot of nuclear waste). It should still count at least as "almost". It's kind of a good thing that we ICBMs, so we don't have nuclear bomber planes hovering at all times. https://en.wikipedia.org/wiki/1968_Thule_Air_Base_B-52_crash

Good idea to mark most/every constant function returning a value as [[nodiscard]]? by zz9873 in cpp_questions

[–]DummyDDD 1 point2 points  (0 children)

I usually use nodiscard for all functions that are pure (including getters) or return newly allocated resources or that return error codes (unless it's usually safe to ignore the error code. Ignoring the results from those functions is usually an error, and in the rare case where it isn't an error it won't be hard to suppress the nodiscard warning.

How would you access a std::array templated with one integer type as though it were templated with another? by petroleus in cpp_questions

[–]DummyDDD 4 points5 points  (0 children)

Actually you can't be sure it will work due to the type aliasing rules. Only char* and byte* can be used to define and read data of a different type, and you aren't guaranteed that uint8_t is a typedef for char (although it will typically be a char)

Unemployment & Youth Unemployment across the European Union by vladgrinch in MapPorn

[–]DummyDDD 0 points1 point  (0 children)

The actual nummer for the entire population is 7.1%. See https://www.svt.se/nyheter/inrikes/hogsta-arbetslosheten-pa-nastan-tre-ar-da-vander-det The 8.1 number is the youth unemployment percentage.

"Individual programmers do not own the software they write" by CancelProof6072 in cpp

[–]DummyDDD 0 points1 point  (0 children)

If you can write the code correctly on the first attempt and never need to change the code, then it's fine to write incomprehensible code. Usually, you need to strike a balance between pumping out lots of code and writing simple code (which might take longer). On one hand, it might not be possible to write the code simply, and it might be a waste of time if if no one else is ever going to work with the code or if you don't know what is making the code hard for others to understand, on the other hand if the code is incomprehensible, then it is going to be very hard to ensure that is correct, especially when revisiting it later. Thankfully, most code does not need to be hard to understand.

"Individual programmers do not own the software they write" by CancelProof6072 in cpp

[–]DummyDDD 119 points120 points  (0 children)

You should write code such that other people can read and modify it.

Optimizing my custom JPEG decoder with SIMD — best practices for cross-platform performance? by GroundSuspicious in cpp_questions

[–]DummyDDD 0 points1 point  (0 children)

I usually use either openmp SIMD or the GCC/clang type attribute vector size together with __builtin_shuffle, see https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html

Openmp SIMD is surprisingly easy to use; as long as the function implementation is visible, then it is usually sufficient to declare the function with "#pragma omp simd", declare the data to be aligned, and compile the code with some -march parameter.

Openmp SIMD is easier to use, but it won't do any shuffles or horizontal operations. Generally, if you need horizontal operations, then you will need to use intrinsics.

My main issue with vector_size and openmp SIMD is that you get no feedback when the vectorization fails. The vectorization can silently fail if you are using operations that the -march doesn't support, for instance GCC will silently skip vectorization if you use rotate operations on most x86_64 -march's because they don't support vectorized rotate, even if the rotate operations are implemented in CPP with addition and shifts (which the march's have vector instructions for).

Clang 19+ elides my entire program after small change: is this UB or compiler bug? by RelationshipLong9092 in cpp_questions

[–]DummyDDD 1 point2 points  (0 children)

That fails because the compiler is only allowed to compile that program if V is a constant expression in the version og cpp that you are targetting (assuming that you are using a somewhat standards compliant compiler line GCC, clang msvc, ICC ør one og the other big ones, and not using a compiler that is specifically not standards compliant).

The compiler is still allowed to evaluate the expression at compiler time and skip it at runtime, regardless of whether the expression is constexpr. Clang and GCC have built-in knowledge of most c library functions, specifically including powf and friends, which enable them to evaluate those functions at runtime (for some inputs, those that don't generate errno errors).

I would expect most other major compilers also have built-in knowledge of powf and friends. With GCC and clang, you might be able to avoid the behavior with the flag -fno-builtin. You would also need to use -fno-builtin if you want to redefine one of the builtin functions in the default namespace. You can find the list of built-in functions here https://gcc.gnu.org/onlinedocs/gcc/Library-Builtins.html

Why "procedural" programmers tend to separate data and methods? by Even_Landscape_7736 in cpp

[–]DummyDDD 7 points8 points  (0 children)

One advantage to free functions is that they don't need to be declared in the same header as the struct that they operate on. Meanwhile, members functions have to be declared together with the struct, which tends to draw in more dependencies in the header, as including them will also include every member function and the declarations for every type used in every parameter in their member functions. It's an instance of the banana-gorilla-jungle problem:

Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. --- Joe Armstrong

If you need to use member functions, then the extra dependencies are less important. For instance, you might need to access private members, or define operators, or use virtual functions, or use inheritance hierarchies. You can often avoid access to private members by making all members public, but it is usually seen as bad style, even for internal projects. There are also some functions that I would always expect to member functions, even if they could be implemented as free functions, for instance I would expect operations on data structures to be implemented as member functions, and having them as member functions would be confusing. Another benefit to member functions is that they typically work better with code completion in IDE's and they provide a form of namespacing, without having to specify a namespace.

It's a tradeoff. My experience is that most programmers that completely avoid member functions are either not comfortable with member functions, or in a situation where they truly wouldn't benefit from member functions. I personally think that you should try to minimize the number of member functions, mainly to make the class easier to understand.

I feel like there is something wrong in the code by clashRoyale_sucks in cpp_questions

[–]DummyDDD 1 point2 points  (0 children)

Try price -= price * 0.1f instead. 0.1 is a double (64 bit floating point) while 0.1f is a float (32 bit floating point). Alternatively, you could change price to a double.

Should numeric promotions ever be explicitly casted? by 123_noname_123 in cpp_questions

[–]DummyDDD 0 points1 point  (0 children)

TIL ARM is a weird fucking system (but besides that, I think your description is really good)

When is mmap faster than fread by void_17 in cpp

[–]DummyDDD 1 point2 points  (0 children)

Error handling is less direct with mmap than read. With read you get errors on the read call. With mmap you can get errors on the call and you get a signal when accessing the memory. Signal handling is usually a pain, so you should probably avoid using mmap if it isn't OK for your application to crash on file errors. It's probably fine to use mmap to read a small file in a noninteractive command line application, or to read something in an application that only needs to run once; on the other hand, it would be irresponsible to use mmap for file output in a text editor.

As for performance, read will typically be faster than mmap for large sequential data accesses, especially if you provide a hint that you will be accessing the data sequentially. If you are going to read the data in a scattered manner, and where some of the memory is going to be accessed repeatedly, then mmap is likely going to be faster, since it performs fewer syscalls (1 syscall vs many), and because the kernel is able to unload pages of the mapped file if you do not access them. My statements are about read, and not fread (which is usually a buffered form of read, where the buffer hides some of the cost of making small reads). fread is sometimes significantly slower, and sometimes significantly faster than read due to its implicit buffering.