/tech/ - Technology and Computing

Technology, computing, and related topics (like anime)

Porn boards have been deleted. Orphaned files will be cleared in 3 days, download images if you have hotlinks.


Days left: 34


JulayWorld fallback document - SAVE LOCALLY

JulayWorld onion service: bhlnasxdkbaoxf4gtpbhavref7l2j3bwooes77hqcacxztkindztzrad.onion

Max message length: 32768

Drag files to upload or
click here to select them

Maximum 5 files / Maximum size: 20.00 MB

More

(used to delete files and postings)


Daily(or whatever) Programming Thread Anonymous 08/21/2019 (Wed) 14:47:20 No.8
What are you working on? Wether you just want to show off your shiny new program, or you need help with a programming issues, this is the thread for you!
>>8
I'm working on a basic stack based concatenative language similar to something like forth. I've put it on the back burner for awhile, but I think it's time to work on it again. I was having trouble with a double free when recursively evaluating strings.
>>29
You can catch a surprising amount of double frees and memory leaks just with grep. Something like
[code]
grep "[a-z]alloc" * | wc -l
grep "free" * | wc -l
[/code]
Of course once you start wrapping stuff then that's another problem.
>>8
Hello /tech/! How have you all been doing? Did any of you lose anything when 8chan went down?
>>37
other than an active community? not really
>>35
Thanks, I'll save that. I'll even give it a shot, but I don't think it will help. After putting it aside, I think I know what the problem is. The language has an 'eval' instruction for evaluating whatever's on the top of the stack. Numbers evaluate to themselves, but strings are recursively sent through to be evaluated as code, and I'm pretty sure my builtin eval function is trying to free it each time before it exits.
>hitting a huge wall with webassembly / dealing with the differences with sockets and websockets
Maybe I should reconsider my tools.
>>42
>Maybe I should reconsider my life.
FTFY
>>8
What are the benefits of using Python? Mostly in web development.
>>68
You get to feel like you're sucking dick without actually sucking one.
Learning javascript for a web design assignment, so this is a copy paste languaje?.
>>37
I saved a local copy of my board entirely during the two days before was kill, every thread. I got all the images as well.
>>72
unfortunately, i didn't get the webums and pdfs though. :/
>>38
>>72
I'm glad to hear you all made it out mostly intact.
>>70
So am I.

I have a question for you, /tech/. How do you feel about visual basic and VB script?
>>94
Visual Basic is very antiquated today, even though some industries still use VB.net developers. Since the .NET paradigms are more or less identical in both languages, I'd highly recommend you learn C# rather than VB.net.

C#'s syntax is much more closely aligned with other C-like languages like Java, Python, and C++.

VB script is a useful skill if you work in a heavily Microsoft Office oriented job, otherwise you'd be far better off to learn Python as a scripting language.
Open file (111.86 KB 600x1094 1565475917440.jpeg)
>>95
Thanks for the answer /tech/! That was fast!

If I wanted to code an AI to be my wife, what would be the best language to do so in? C++? Python?
>>96
>If I wanted to code an AI to be my wife, what would be the best language to do so in? C++? Python?
probably better question for >>>/robowaifu/ anon.
>>97
Thanks. I just wanted to see what you guys thought on the matter. The consensus there seems to be that C++ is best.
>>98
Whatever works is what's best anon. I'd say use AI that's already working today. Maybe Microsoft's Bot framework or similar?
https://dev.botframework.com/
>>99
Is code enabled on this board?
>>247
Good. It is. I have a coding question, /tech/. I am currently doing a school project on javascript and HTML. Unfortunately my code isn't working and I am not sure why. I ran it through some code validators and the answers it gave me was inconclusive.
The program I am writing would work like this. The user enters their name into the "your name" box then they enter their grade number in the "your score". So for example they would enter 85. Then my program would tell them ",you have a B, which is above average. Good job!". However, this is not happening. Can you please tell me what I am doing wrong, /tech/?

<!DOCTYPE html>
<html>
<head>
<title>If/Else</title>
<script type="text/javascript">
function changeText() {
var firstName = document.getElementById("fNameBox").value;
var score = document.getElementById("scoreBox").value;
var result;
if (score >= 90){
result = ",you currently have an A. Great work!";
}
else if (score >= 80 && score <= 89) {
result = ",you have a B, which is above average. Good job!";
}
else if (score >= 70 && score <= 79) {
result = ",you have a C, which is average. You could be doing better but at least you're passing.";
}
else if (score >= 60 && score <= 69) {
result = ",you have a D, which is below average and is failing. You need to improve your grade.";
}
else (score >= 0 && score <= 59) {
result = ",you have a F, which is failing. You need to improve your grade or you will fail this course.";
}

document.getElementById("message").innerHTML=(firstName + result);
}
function clearText() {
document.getElementById("message").innerHTML=("<br>");
document.getElementById("fNameBox").value = "";
document.getElementById("scoreBox").value = "";
}
</script>
</head>
<body>
<div id="main">
<div id="header">
<h1>Program 6 - Grading challenge - anon</h1>
</div>

<form id="myForm">
First name: <input type= "text" id ="fNameBox">
<br><br>
Your score (from 100 to 0) <input type= "text" id ="scoreBox">

</form>

<p id="demo">Output:</p>
<p id="message"> <br> </p>

<button type="button" onClick="changeText()">Submit</button>
<button type="button" onClick="clearText()">Clear</button>
</div>
</body>
</html>
>>249
You forgot an "if" in the last branch when checking the score.
[spoiler]
You might want to use a numeric input for the score, instead of a textbox.
[/spoiler]
Open file (142.50 KB 900x900 terrydavishoodie..jpeg)
>>250
Thank you, /tech/. That was a very fast response. I have the text box there as that was what my teacher instructed me to do.
>>249
also the elses are useless in this case, as only 1 of the ifs can match anyway because your conditions are disjoint.

and note that <button> is always a button. only <input> needs a type="button" to become a button, or, you know, a type="submit" or even type="reset" which clears out your fnamebox and scorebox by default.
>>252
fuck, i'm used to asterisks resulting in bold text, not spoilers.
>>252
So it would have just been better to write "if" instead of else if like this?

<!DOCTYPE html>

<html>

<head>

<title>If/Else</title>

<script type="text/javascript">

function changeText() {

var firstName = document.getElementById("fNameBox").value;

var score = document.getElementById("scoreBox").value;

var result;

if (score >= 90){

result = ",you currently have an A. Great work!";

}

if (score >= 80 && score <= 89) {

result = ",you have a B, which is above average. Good job!";

}

if (score >= 70 && score <= 79) {

result = ",you have a C, which is average. You could be doing better but at least you're passing.";

}

if (score >= 60 && score <= 69) {

result = ",you have a D, which is below average and is failing. You need to improve your grade.";

}

if (score >= 0 && score <= 59) {

result = ",you have a F, which is failing. You need to improve your grade or you will fail this course.";

}



document.getElementById("message").innerHTML=(firstName + result);

}

function clearText() {

document.getElementById("message").innerHTML=("<br>");

document.getElementById("fNameBox").value = "";

document.getElementById("scoreBox").value = "";

}

</script>

</head>

<body>

<div id="main">

<div id="header">

<h1>Program 6 - Grading challenge - anon</h1>

</div>



<form id="myForm">

First name: <input type= "text" id ="fNameBox">

<br><br>

Your score (from 100 to 0) <input type= "text" id ="scoreBox">



</form>



<p id="demo">Output:</p>

<p id="message"> <br> </p>



<button type="button" onClick="changeText()">Submit</button>

<button type="button" onClick="clearText()">Clear</button>

</div>

</body>

</html>
>>253
to do a bold text you would use 3 of the apostrophes so like this
thanks for the help on my work
>>253
I forgot to add this in my post but here is the page where you can find all the ways to format your text.
https://julay.world/.static/pages/posting.html
>>254
yes. else if becomes important when there's overlap in your conditions, like
if (score >= 90) {
result = ",you currently have an A. Great work!";
}
else if (score >= 80) { //`score <= 89` is implicitly true because `score >= 90` failed
result = ",you have a B, which is above average. Good job!";
}
else if (score >= 70) { //same as above
result = ",you have a C, which is average. You could be doing better but at least you're passing.";
}
else if (score >= 60) {
result = ",you have a D, which is below average and is failing. You need to improve your grade.";
}
else { //you already handled all conditions for getting an A-D, so what's left is giving an F
result = ",you have a F, which is failing. You need to improve your grade or you will fail this course.";
}
>>262
the basic point that anon may not be realizing yet about
if {
}
else if {
}
else {
}
code blocks is that they optimize the runtime performance by skipping unneeded processing (for instance, you've already found the foo, so no need to keep looking, etc). The code structure may also be important to your algorithm's codeflow as well ofc.
>>278
Thanks for pointing that out. I apperciate the help, /tech/!
A question I have regarding the code you posted, is there ever a time where I would write just else and not else if? I did in my own code and it didn't work but I see you did it in your code. Can please explain this? Please get back to me when you can, /tech/. Thank you.
>>285
>is there ever a time where I would write just else and not else if?
Oh sure, in fact it's probably much more commonplace in most codebases anon. E.G.,
if (eats_cake && is_kike)
its_cakejew = true;
else
its_cakejew = false;


You want to test a logic state. If it's true then you take one path in the code, if it's false you take the other. Make sense anon?
Open file (2.41 MB 4608x3456 boomerusa.jpg)
>>289
Thanks for the explanation, /tech/. If I need anymore help with my work, I'll come back here.
I am pretty certain my dad uses this board as well, which is something I find kind of funny
>>290
You can also nest logical tests, basically endlessly. For example, let's say you wake up in the middle of the night and realize your beautiful code might accidentally tag some other cake-eating kike accidentally as cakejew. You decide you can do a second test just to be sure:
if (eats_cake && is_kike) {
if (is_fat_fuck && is_lol_cow)
its_cakejew = true;
}
else
its_cakejew = false;

That way you can be sure.

Orly? Can you say GTFO to him for us anon?
>>278
>runtime performance
Cute. But you still evaluate all the conditions when none match, and when the whole class gets an F, that's all the time. If you have a very good reason to have heavy computations in your else if conditions, you may see a slight speedup compared to if ... if. But 99.99% of the time you won't notice, even in production code.

The real advantage of else if is that it can only run *one* of the code blocks, which makes reasoning about the code so much easier. With an else at the end you even have the guarantee that *exactly one* of the branches will be run.

Likewise, in this case you want to map a score to a message, so really you should have that mapping as data and a function to perform that mapping:
const scoreMap = [
[[ 0, 60], "you have an F, which is failing. You need to improve your grade or you will fail this course."],
[[60, 70], "you have a D, which is below average and is failing. You need to improve your grade."],
[[70, 80], "you have a C, which is average. You could be doing better but at least you're passing."],
[[80, 90], "you have a B, which is above average. Good job!"],
[[90,101], "you currently have an A. Great work!"]
]

// Assumes an iterable object with entries of the form [[lowerBound,upperBound], value].
// Searches for the [lowerBound,upperBound) range that contains the key,
// including lowerBound and excluding upperBound, and returns its value.
function findInRanges(map, key) {
for (const [[min,max], value] of map)
if (min <= key && key < max)
return value
}

function changeText() {
const fNameBox = document.getElementById("fNameBox")
const scoreBox = document.getElementById("scoreBox")
const message = document.getElementById("message")

const name = fNameBox.value
const score = parseInt(scoreBox.value)

message.innerText = `${name}, ${findInRanges(scoreMap, score)}`
}

Ideally, you would use a static ordered map in this case and call lower_bound to get the right message in logarithmic time, or even a lookup table to get the right category in constant time:
const pointsToLetter = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDDDDDDDDDDCCCCCCCCCCBBBBBBBBBBAAAAAAAAAA"
const letterToMessage = {
F: "you have an F, which is failing. You need to improve your grade or you will fail this course.",
D: "you have a D, which is below average and is failing. You need to improve your grade.",
C: "you have a C, which is average. You could be doing better but at least you're passing.",
B: "you have a B, which is above average. Good job!",
A: "you currently have an A. Great work!"
}

...

message = letterToMessage[pointsToLetter[score]]
>>293
>The real advantage of else if is that it can only run *one* of the code blocks, which makes reasoning about the code so much easier. With an else at the end you even have the guarantee that *exactly one* of the branches will be run.
all good points, but implying that a specific code path taken in 99.99% of the cases is irrelevant to perf is just silly.
>also
you're code formatting looks like shit anon.
>>293
>>294
Two words:
clang
format
>>296
Go pull it through clang-format. Looks like garbage, most notably because it fails to understand the implicit ; after the map definition.
>>298
no thanks.
>most notably because it fails to understand the implicit ; after the map definition.
the formatter's area of responsibility doesn't include the coder's incompetence. GIGO anon.
Open file (319.17 KB 1300x1108 1960'sbackyardbbq.jpeg)
Open file (186.85 KB 1200x800 1950scookout.jpeg)
Open file (193.56 KB 912x1200 iowahattip.jpg)
Open file (43.85 KB 680x412 boomerfishing.jpeg)
>>292
>>294
>>295
>>296
>>298
>>299
Thanks, /tech/. I really admire all the amazing minds here that are willing to help. Also, I am pretty certain my dad is here to stay. He'll make you a burger on the grill if you're nice enough and understand the value of hard work.
(^:
>>294
>const pointsToLetter = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDDDDDDDDDDCCCCCCCCCCBBBBBBBBBBAAAAAAAAAA"
holy autism, don't actually do this unless you're autistic
>>294
I'm only linking to your post as a simplification. You're mistaken about the advantages of if in a way, because these are better achieved by a case. In particular, a case, depending on the language, can ensure that: all possible values are given treatment, only one case is selected, and can be optimized to O(1) or not by the compiler based on how appropriate this is.

Now, my first thought is to reduce the problem space, since all of these scores are evenly on boundaries of ten, and so the grade could be divided by ten to shorten this, but there are better ways for some languages. Follows is this example in Ada:

type Letter_Grade is (A, B, C, D, F);
type Number_Grade is new Integer range 0 .. 100;

function Grade (Score : in Number_Grade) return Letter_Grade is
begin
case Score is
when 90 .. 100 => return A;
when 80 .. 89 => return B;
when 70 .. 79 => return C;
when 60 .. 69 => return D;
when 0 .. 59 => return F;
end case;
end Grade;


I actually made a mistake when I was writing this; I repeated 60 for D and F, but the compiler was able to tell me about this and refuse to compile it. Know that you can use others in a case to avoid needing to list cases you don't care about, but it can also be dangerous for this precise reason. When you enumerate all cases, as I've done here, the compiler can tell you when you make a mistake or the type changes to have new cases, whereas use of others will hide this. As an example of a different mistake I could've made, imagine I made the first case 90 .. 99; if I'd used an others, then a score of 100 would've resulted in an F.

This is neat, isn't it?
>>312
>red text
>uses autism twice in one sentence
>completely missing the point
go back to hello world

>>323
Yes I wholly agree, proper case statements are the way to go, specifically ones that allow ranges in this case. Unfortunately javascript's switch is barely better than C's (you can match on any object instead of primitives only, but now you can put arbitrary expressions with side effects in there too), so any mapping from points to grades is ugly at best or blatant abuse of switch (true) at worst.

>all possible values are given treatment
From what I understand from the manual, Ada can't check totality or overlap when you use ranges directly. Does it complain if you subtype the grade into IsF is Number_Grade 0 .. 59 etc and then make IsF 50..59 or 0..64?
>>327
>go back to hello world
no he's right, it's complete autism--and i do understand the point. A) you do realize you were answering a beginner right? B) explain in detail how your const string would appear in the code w/o some kludgy hackery beforehand.
>>327
>From what I understand from the manual, Ada can't check totality or overlap when you use ranges directly.
If you use a case with ranges, it can still determine if every possible value is covered or not. There are rules about case values and other things that ensure this can be checked during compilation.
>Does it complain if you subtype the grade into IsF is Number_Grade 0 .. 59 etc and then make IsF 50..59 or 0..64?
So IsF is a subtype of Number_Grade here. This still works:

type Letter_Grade is (A, B, C, D, F);
type Number_Grade is new Integer range 0 .. 100;
subtype Is_F is Number_Grade range 0 .. 59;

function Grade (Score : in Number_Grade) return Letter_Grade is
begin
case Score is
when 90 .. 100 => return A;
when 80 .. 89 => return B;
when 70 .. 79 => return C;
when 60 .. 69 => return D;
when Is_F => return F;
end case;
end Grade;


If I were to change the range of Is_F, the case would complain about unmet possibilities or overlapping.
Hello again /tech/, it's me >>249 I got another programming question again. Why does it tell me that the number is undefined? What am I doing wrong, /tech/? My teacher told me to comment the else if statements so if you were wonder why they were like that, that's why.


<!DOCTYPE html>
<html>
<head>
<title>Switch</title>
<script type="text/javascript">
function changeText() {
var firstName = document.getElementById("fNameBox").value;
var number = document.getElementById("numberBox").value;
var result;
number = parseFloat (number);
/*
if (number == 1) {
result = "one";
}
else if (number == 2) {
result = "two";
}
else if (number == 3) {
result = "three";
}
else if (number == 4) {
result = "four";
}
else if (number == 5) {
result = "five";
}
else {
result = "over the number 5";
}
*/
switch (number) {
case 1:
result = "one";
break;
case 2:
result = "two";
break;
case 3:
result = "three";
break;
case 4:
result = "four";
break;
case 5:
result = "five";
break;
default:
result = "oops, your nubmer is over the number 5";
break;

}

document.getElementById("message").innerHTML=(firstName + ", " + number + " is written " + result);
}
function clearText() {
document.getElementById("message").innerHTML=("<br>");
document.getElementById("fNameBox").value="";
document.getElementById("numberBox").value="";
}
</script>
</head>
<body>
<div id="main">
<div id="header">
<h1>Program 7 - Written number program - anon </h1>
</div>

<form id="myForm">
First name: <input type= "text" id ="fNameBox">
<br><br>
Enter a number (from 1 to 5): <input type= "text" id ="numberBox">
</form>

<p id="demo">Output:</p>
<p id="message"> <br> </p>

<button type="button" onClick="changeText()">Submit</button>
<button type="button" onClick="clearText()">Clear</button>
</div>
</body>
</html>
>>382
Works on my machine™.
What input do you give it?
Open file (1.88 MB 540x360 1568130941831-4.gif)
>>385
I tells me the number is undefined. It doesn't matter since I didn't turn it in on time and got a 0 on it. It's not a big deal. Thanks for the help anyways, /tech/.
>>392
You should always just turn in whatever you have before the deadline anon. Partial credit is better than no credit tbh.
>>393
Valid point, anon. I am going to do that with my political science class.
>>392
Does it tell you the number is NaN or do you get an actual "number is undefined" error in the console?
Even if you didn't submit it on time, it's still a learning experience you shouldn't (rather, you mustn't) ignore.
So, what input did you give it?
Open file (140.66 KB 326x385 1543413326155.png)
Reminder that this little crybaby learned to program and built her own game engine from scratch in her summer break. How long did it take you to learn?
>>37
>Did any of you lose anything when 8chan went down?
The last bit of feels anons didn't know they had for the niggers that were behind it perhaps?
What's the best book to learn C with?
Open file (115.75 KB 1900x706 Selection_337.png)
>>249
>Can you please tell me what I am doing wrong, /tech/?
Spending time on an imageboard instead of shitposting irl.
>>249
>>250
Apart from the if else issues there's a lot of other shit...

The GUI is shit (no inline CSS at least), no use of fieldset, or legends.
Notice the changes I've made in this example, the data flow is clearer - this helps remove errors from the task being performed (usability, UI, UX, HID, blah, blah....)
I also swapped out the output paragraph <p> for an in-form textarea element, but changed it's attribute to read only. This allows the output in that textarea to be acted upon by the interface as normal (e.g. select/copy functions will work *exactly* the same as they do for normal input fields) - BUT not allow it to be edited. If you use a paragraph this would be undefined behaviour based on the general CSS/Jscript applied to the <body><p> tags. Using an additional "disabled" attribute on the textarea would gray-out the field - but this would not be good for readability).
Notice how the field default input is a non-breaking space (the trick to use if you want an invisible null character). I added in relevant '\n' newlines and shifted the commas around accordingly.
Add in CSS, code indentation, and MUCH more importantly data sanitization checks yourself - (you did try entering "foobar", or "6000000" for your score right?)

*HTML5 now has an <output> element you would use like you did with the <p> element, but older browsers may not recognize it, so I erred on the side of portability and used <textarea>.


<!DOCTYPE html>
<html>
<head>
<title>If/Else</title>
<script type="text/javascript">

function changeText() {
var firstName = document.getElementById("fNameBox").value;
var score = document.getElementById("scoreBox").value;
var result;
if (score >= 90){
result = "you currently have an A.\nGreat work!";
}
else if (score >= 80 && score <= 89) {
result = "you have a B,\nwhich is above average.\nGood job!";
}
else if (score >= 70 && score <= 79) {
result = "you have a C,\nwhich is average.\nYou could be doing better but at least you're passing.";
}
else if (score >= 60 && score <= 69) {
result = "you have a D,\nwhich is below average and is failing. You need to improve your grade.";
}
else if (score >= 0 && score <= 59) {
result = "you have a F,\nwhich is failing.\nYou need to improve your grade or you will fail this course.";
}

/*document.getElementById("message").innerHTML=(firstName + result);*/
/*document.getElementById("output").value=(firstName + result); /* I used this when outputing to an un-editable input element*/
document.getElementById("output").innerHTML=(firstName + ',\n'+ result);

}

function clearText() {
document.getElementById("output").innerHTML=("&nbsp;");
document.getElementById("fNameBox").value = "";
document.getElementById("scoreBox").value = "";
}

</script>
</head>

<body>
<div id="main">
<div id="header">
<h1>Program 6 - Grading challenge - anon</h1>

</div>
<form id="myForm">
<fieldset>
<legend>Data Entry</legend>
First name: <input type= "text" id ="fNameBox">
<br>
Your score (from 100 to 0) <input type= "text" id ="scoreBox">
</fieldset>
<fieldset>
<legend>Form Action</legend>
<button type="button" onClick="changeText()">Submit</button>
<button type="button" onClick="clearText()">Clear</button>
</fieldset>
<fieldset>
<legend>Data Output</legend>
<textarea id="output" rows=5 cols=40 readonly>
&nbsp;
</textarea>
</fieldset>
</form>

</div>
</body>
</html>
>>417
>What's the best book to learn C with?
The one written by the authors of C maybe? See >>8
In reality - whatever book works for you, then try some others to cover the bits you missed with that book, because no book is perfect.>>35
>>417
Learnin C itself isn't too difficult.
If you know jack shit about programming then the K&R is probably the best, because both the examples and the excercises are small but complete enough to teach you a lot. Some of them are even based on real-life use cases.
If you already know some languages then anything is fine. The most obscure parts (including differences between versions of the standard) rarely are explained in enough details, if at all.
The real difficulty is learning "the C standard library", which is what you're going to use most while writing C.
Unlike the language itself, the standard library is full of caveats and you will check the reference manual pretty much any time you want to use a function from there.
Even a straightforward function like malloc (allocate a block of memory of size specified by the function argument) can behave in surprising ways in certain cases (for example, the argument can overflow or underflow. The calloc function doesn't have this problem.)
>>419
>>420
Helpful. Thanks, mates.
>>418
>heavy dose of autism
>doesn't go all the way
Now this is pod racing: https://jsfiddle.net/tkpb5udn/1/
Of course this is only relevant to the professor who should update his course material from 15 years ago and anons who want to learn proper HTML5.

>*HTML5 now has an <output> element
Good call. It has the right semantics and even an aria-live role in most browsers, so blind people and tards get to hear their grade automatically.
>older browsers may not recognize it
>implying Chrome <10, Firefox <4 and IE exist
Regardless, HTML5 says any unknown tag must be treated as basically a <div>. You're free to use stuff like <dialog> or <details> or whatever and have it look like shit on some browsers until you polyfill it.

Protip when doing webdev: never use .innerHTML, always use .textContent or .values. If you need fresh nodes, use document.createElement, copy a bunch of existing nodes, copy from a <template> or at least use a library that sanitizes your HTML.
>>420

> for example, the argument can overflow or underflow. The calloc function doesn't have this problem

Wait what? malloc takes a size_t for number of bytes, calloc takes 2 size_t's for number of chunks and size of chunk, but in both cases size_t can overflow or underflow. That's not a problem with malloc or calloc though, that's just regular integer overflow.
>>426
>That's not a problem with malloc or calloc though, that's just regular integer overflow.
ofc it's an issue with them. unguarded memory allocations can always be out of range, regardless of the numerical specification. this is why having humans responsible for resource management (C being the worst general case) is always a bad idea; we're notoriously bad at it. RAII is the way to go.
>>426
True, but calloc (and reallocarray) return NULL and sets errno when the argument overflow.
malloc and realloc just take a single argument (usually a multiplication between an integer and a call to sizeof) without making checks, so you can get out-of-range allocations like >>427 says and other "fun" things.
That's why calloc doesn't have a problem with integer overflow, because if it happens it returns NULL, not a valid pointer pointing to invalid places.
>>429
again, the issue isn't 'integer overflow' it's allocations to out of range allocations. calloc() is no better at preventing this than malloc() is. you're still leaving the choice in the hands of a human rather than the runtime.
>>430
No, it has nothing to do with manual allocation. It has to do with the fact that functions have caveats regardless of their purpose, and that's why I wrote in >>420 that a beginner will read the standard library manual any time a standard function is needed.
As for memory allocation, malloc doesn't guard against allocations caused by integer overflow while calloc does and returns NULL and sets errno when that happens, so a simple NULL check on the returned pointer is enough to catch problems caused by overflows.
Certainly allocations managed by the runtime are better, but C doesn't have that and we are talking about C not some other language, so try to stay on topic.
>>431
'we're' talking about proper resource management, not the caveats of C. As you're obviously obsessed about the idea of 'integer overflow' as if that were the fundamental issue as opposed to the actual issue of the memory itself it hardly seems beneficial to continue the debate.
>>432
>>417 asked about books to learn C.
In >>420 it's adviced to watch out about the standard library's caveats (and thus C's caveats, since they are connected), integer overflow in malloc is used as an example.
>>430 then starts talking about manual resource management which has nothing to do with the topic at hand.
>inb4 triggered or whatever meme is popular nowadays
Sure why not.
Open file (3.80 MB libc.pdf)
>>417
Straight from the library's documentation.
Open file (563.35 KB 2560x1440 YouWaShock.jpg)
Today in my Electrics course, we were doing combination circuits, and once I understood how to do them, I figured I'd try to automate the summation of total resistance over an arbitrarily sized parallel circuit, since I haven't really had a nice practice project to work on, and I'm rusty as hell. Also this would obviously make solving these problems much less tedious. I started off just automating the summation of resistance over an 'n' path parallel circuits, but as time went on, I got more and more ambitious. Six hours and eight cups of coffee later, I'm trying to figure out how to represent a combination circuit with 'a' elements, where each element can be either a resistor, with it's resistance measured in ohms, or a branch, which can have 'b' number of paths. Each path can have, of course, 'c' number of elements in them, which can again be either resistors or subsequent paths. I want to be able to obviously represent this circuit structure, and move across it to compute the summation of each parallel branch (which for those who don't know, can expressed as (1 / { 1/r[1] + ...1/r[n] } ), and then combine them with each other element in series in the main circuit (the total resistance of which is simply additive). I'd also like to ideally allow the user to access, add, or remove any element or sub-element within the circuit.

....I only know C and C++.

I'm an intermediate level programmer, and I'll admit I don't know much about more advanced data structures and databases. What's my next step here? Should I learn how to work with databases? Will biting the bullet and picking up a scripting language of some sort make my life easier? I'm a bit of a stubborn autist, and I'm invested in this problem now. Pic related is my cave-man scribbles on my whiteboard as I desperately try to figure out what the fuck I'm doing.
>>446
>Should I learn how to work with databases? Will biting the bullet and picking up a scripting language of some sort make my life easier?
Neither of those would simplify your program, and databases would just make your code uglier and slower. Your biggest issue is probably that you seem to be using rules for parallel and sequential circuits to reduce the circuit down, which doesn't work for arbitrary circuits (the wheatstone bridge, for instance). Instead, store the circuit as a tree with each node containing references to its parent nodes and child nodes, as well as its resistors, and apply kirchhoff's loop rule and junction rule to obtain a system of equations. Then you can apply some simple linear algebra routines to solve the circuit.
>>446
Very interesting sounding project anon. How's it coming?
>I only know C and C++
Good. Then you should be able to create something that actually works. I handle pretty complex data structures and transformations on them in a fairly straightforward fashion using nothing but the C++ standard library containers and algorithms. I'd recommend the same for you. I agree with the other anon that databases certainly won't help here. Do it all in memory and write out data to files if needed using simple text.

Good luck anon, let us know how it goes.
Open file (53.42 KB 179x158 faggot dog.jpg)
>>252
Not quite, if you specify a button without a type inside of a form it will default to "submit", which may not be the behaviour you want if your page has interactive elements.
>>461
Just to prove my point.

https://jsfiddle.net/gycmfnka/
>>446
>Will biting the bullet and picking up a scripting language of some sort make my life easier?
Yes, C++ is verbose and every language feature is made with performance in mind instead of reducing mental gymnastics.

Ignoring unknown resistors and complex circuits that require systems of equations, let's start off with expressing your data in a logical way. Every (sub)circuit is either a single resistor with a resistance, a bunch of circuits in series (see your main and the circuits in the branches) or a bunch of circuits in parallel (see your branch). Note the "bunch of circuits": each element may be any one from those 3 categories and your series or parallel circuit doesn't care. Also there's nothing special about your main circuit, it's just a series circuit.

data Circuit = Series [Circuit]
| Parallel [Circuit]
| Resistor Ω

(Feel free to use any other notation, but this one happens to be valid Haskell code.)
With this you can already build some examples to check if you have all the types you need:

example = Series
[ Resistor 500
, Resistor 600
, Parallel
[ Series
[ Resistor 200
, Resistor 100
]
, Series
[ Resistor 4
]
]
, Resistor 300
]

That seems about right. It's your whiteboard example with some random resistor values.

To get the resistance of any circuit, we have to consider three cases: when the circuit is just a single resistor, a series circuit or a parallel circuit. The single resistor is piss-easy: it's just its value

resistance :: Circuit → Ω
resistance (Resistor v) = v

A series circuit is basically as easy: take the sum of all subcircuits

resistance (Series subcircuits) = sum resistances
where resistances = map resistance subcircuits

Parallel circuits are the least trivial because you have to sum over the reciprocal resistances and take the reciprocal again:

resistance (Parallel subcircuits) = recip (sum (map recip resistances))
where resistances = map resistance subcircuits


As this is all valid Haskell, you can run resistance example and more: https://repl.it/repls/DecentUntimelyPlan . Let the compiler derive a Show and Read for circuits and you get a parser and a printer for free.

You can write similar code in C++ using subclasses for the different flavours of circuits: https://onlinegdb.com/HkzZpeBFS . It's just not as pretty at 60 lines C++ for the basics compared to 10 in Haskell.

>access, add, or remove any element or sub-element
use javascript
The browser is the only easy and sensible GUI toolkit.
>>454
>kirchhoff's loop rule and junction rule
neat. found this, thanks anon.
https://courses.lumenlearning.com/physics/chapter/21-3-kirchhoffs-rules/
>>464
>The browser is the only easy and sensible GUI toolkit.
Truly we live in one of the shittier universes.
>>466
It could be worse, like a universe where one company has the lion's share of web searches, online advertising and browser use and is basically defining web standards because no one can say no.

oh, nvm
Open file (1.64 MB 2000x1000 theone.jpeg)
Hey /tech/, I got a question for you regarding the modding of a video game. I wanted to develop a mod for a video game and that said video game's source code had not been released yet, would that complicate things and make development of a mod harder when compared to a video game that did have its source code released?
>>471
If the game does not support modding out-of-the-box (e.g. through an ad-hoc scripting language) then having the source or not doesn't change much.
Maybe you will save time because you don't have to reverse engineer the thing, but that's it.
>>471
If you have to ask, then it's safe to assume the question is purely rhetorical. Thanks for stopping by, come again.
>>472
>>474
Thanks for the answers, /tech/. I appreciate the assistance.
>>496
heh, alright you fucker :^). the answer is obviously it would simplify things, even if the game didn't support modding out of the box. it will allow you to understand more about how the memory structures came to be in the state they are as you hack around with a hex editor. this can help you know better where the memory boundaries are hard-and-fast, and where you can tweak them a bit.

either way, it's not an easy task for anyone tbh particularly an amateur. good luck.
Trying to do a project on django, shit doesn't work because the library does a bunch of implicit hidden stuff that crashes itself.
>>596
>django
any idea where the problem is arising?
howdy, this looks like the right place for this, if not tell me and i'll fuck off.

I'm an old school ME who started when cad was about the only sort of programming needed to get the job done, i'm looking to learn a programming language that would work well in the world of automation but also give me reach outside of my current industry should anything happen to the niche i am in...

basically i've more or less settled on python, what do you guys think? you think that's a good place to start and invest my time in? if you guys know anything about siemens controls is python in the same wheel house? how's it to jump from python to the various manufactures control languages in automation?
as it stands it's just my job to spec the robots and components for the production lines i design, i know jack and shit about the actual controls beyond a basic understand that some are more complex than others....that said,i'd also like to be able
make use of the language i invest in to be usable outside of automation..i know that's vague as fuck but i really don't have any predefined goals and this is all for my own personal betterment and interest,so maybe making applications and programs for personal projects would be cool...i don't know what, it just needs to be useful..lol..fml

i fully expect to get reamed because i am a moron and don't know what i am doing or even what it is exactly i want rather than just a general idea,it's cool i can take it and probably deserve it on some level, just try to spit in the hole first and at least point my dumb ass in the right direction.
gentlemen,i thank you for your time and again, sorry for the faggotory.
Open file (10.45 MB 608x1080 dancingrobotwithskin.webm)
>>601
I've asked completely beginner tier questions and have gotten full, detailed answers. Don't feel embarrassed to ask questions as long as it is a sincere question.
Video unrelated.
>>601
While I"m not a huge fan of the language the way it's typically shilled on the /tech/s, C is probably a better choice from the sound of your goals, IMO.
A) You're already an experienced ME, so you'll have the mental chops to lift yourself out of the C-maymay trenches.
B) C is literally the software these control systems typically run on.

It's a simple language and the basics can be picked up in a day if you're smart (and you obviously are). But it's filled with so many gotchas, corner-cases, and tricky, hard-to-master idioms that to become a true expert at it takes years of dedicated effort and a true talent for understanding (and anticipating) the unseen.

Understanding Finite State Machines and PLCs w/ Ladder Logic is the bread and butter of these types of control devices Siemens and other manufacturers provide.

All that said, Python is a growing power in many domains, including automation. You'll never be a true master in this field if you stagnate at just Python, but it may be one of the least painful ways to get started.

C++ would also be a good choice. If you want to explore that direction, Stroustrup's PPP2 would be a good starting place.

Good luck anon.
>>621
thanks for the response, i think i'll start with c++, i've been told for years to learn C++...i was just thinking python might be a more contemporary choice, as for painful to learn, bring it, i'm not one to walk away from difficult things...i just need to know my efforts are being well spent....i'm aware of ladder logic and plc's but have no idea what language they are written in. thanks again for the guidance.
>>633
YW. C++ is by far my favorite programming language.

>i'm aware of ladder logic and plc's but have no idea what language they are written in
any language, really. after all it's just a description of logic. The practical reality in the real world is that the engineers who devise the devices often all create the kits for them, so generally C or C++ to start with.
I'd like to learn via daily video tutorial but all the ones I've found are pajeet shit that spend 4 or so lessons teaching how to install a Windows-centric IDE then giving C scripts that are somewhat esoteric to the IDE (that is, not requiring special Include libraries to be defined), leading me to look up more.

Should I really stick to the book? My computer screen proportions makes reading PDFs unfun. Can anyone recommend me a good tutorial on C?
Answer to yester-yesterday question on nipcuck/g/. Only 20 LOCS. Feel free to implement argc, argv and their respectful checks. I'm okay with the results. Please like and subscribe! I hope code tags work this time as well as indentation

#include <stdio.h>
#include <string.h>

void owofy (const char in[], char out[], const int len) {
int i = 0, off = 0;
for (i; (i < len) || (in[i] != 0); i++) {
if ((in[i] == 'i') || (in[i] == 'e')) {
out[i + (off++)] = 'w';
}
out[i + off] = in[i];
}
strncpy (out + i + off - 3, " owo", sizeof(" owo"));
}

int main (void) {
char buf[] = "niggers are curahzee", swap[80];
owofy (buf, swap, sizeof(buf) / sizeof(buf[0]));
printf ("input>\t%s\noutput>\t%s\n", buf, swap);
return 0;
}
>>658
>Can anyone recommend me a good tutorial on C?
Kernighan a Ritchie's book. There is literally nothing else that is both simple and complete. Anything else will only badly teach you a subset of the language.
If, after reading the book, you still can't use the language, then nothing will help you.
>>658
Here's a cheat sheet documentation for C https://learnxinyminutes.com/docs/c
Any ziggers ziguanas here? Trying in vain to escape C, but without fail every memelang I've tried is broken vaporware. I've been trying to implement some generic containers but for some reason the compiler keeps complaining about "cannot assign to constant" even though there's very little "constant" to assign to.

Minimal main.zig example:

const std = @import("std");
const Allocator = std.mem.Allocator;

pub fn exampleContainer(comptime T: type) type {
return struct {
allocator: *Allocator,
data: []T,

pub fn init() @This() {
return @This() {
.allocator = std.heap.direct_allocator,
.data = [_]T{},
};
}

pub fn resize(self: @This()) !void {
self.data = try self.allocator.realloc(
self.data, 5);
return;
}

};
}

const exampleContainerType = exampleContainer(u8);

pub fn main() anyerror!void {
var container : exampleContainerType = exampleContainerType.init();
try container.resize();
return;
}


Compiler error:

/mnt/misc/Scripts/Tests/zig_error_min/src/main.zig:18:25: error: cannot assign to constant
self.data = try self.allocator.realloc(
^
/mnt/misc/Scripts/Tests/zig_error_min/src/main.zig:30:5: note: referenced here
try container.resize();
Open file (68.63 KB 1200x1349 1200px-ISO_C++_Logo.svg.png)
>>677
>but without fail every memelang I've tried is broken vaporware
Well, quite simply, stop using meme languages bro.
>>>/robowaifu/12
Sepples may be a mess, but at least it actually works in fact of course.
>>678
>Compile times
>Largrely dragged behind by all of the language features that you probably shouldn't even use but are there for backwards compatibility
>One metaprogramming language (C preprocessor) is inherited from C, still carrying all the same baggage associated
>One metaprogramming language (templates) is built around the entire accident of a language feature managing to be Turing-complete, written as a bunch of unreadable esoteric hacks designed in a syntax that wasn't intended for them and a bunch of patches on top of those hacks and a bunch of hacks on top of those patches that lead to exponential compile times and unparsable errors, abusing other language features in ways that they were not intended for (What are std::conditional_t, std::is_void? They're templates that turn into structs and classes pretending to be compile-time evaluated functions!)
>std::basic_string<_CharT, _Traits, _Alloc> &std::basic_string<_CharT, _Traits, _Alloc>::append(_InputIter, _InputIter, std::input_iterator_tag) [with _CharT=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char>, _InputIter=std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>]
>One metaprogramming language (constexpr) is implemented as an afterthought but at least it kind of looks like something vaguely readable, if C++ weren't already polluted with all of the template bullshit
>ABI compatibility? What's that?
>RAII is OK, except when you remember that members' positioning in memory is also coupled with construction/destruction order--then it's back to "writing C++ like C with new and classes" which you're apparently not supposed to do...
because C++, too, is a meme. It's just a very big meme.

I think Terra was the language I found that came closest to getting it right. Metaprogramming is fundamentally for the convenience of the programmer, so it ought to be convenient (as in, anything but templates) and not sluggish. And metaprogramming operates under a different set of concerns compared to the actual low-level work, so it ought to be done in a different language, but still aware of the low-level components (unlike the C preprocessor). Unfortunately it's a major PITA to build and the original developer basically abandoned it at birth, and it's basically been stuck in development limbo ever since.

If it actually worked, Zig would be decent enough for my uses. It mostly takes the "if constexpr" approach to metaprogramming and properly represents "generics" as functions of some sort (even though it makes the mistake of conflating the metaprogramming components and the low-level components within the same language). It's not perfect, but I hoped that it would be good enough for what I'd be trying to do.
>>681
>knows more about industrial-grade programming than millions of men actually out there doing it.
>*wipes cheetos dust off mouth and grunts*
<nah, it's just a meme
>>684
This is why Windows is the best OS ever made.
>>685
Because of fat, ill-informed and arrogant retards? Probably true. That and stronk, independents and poo-in-loos everywhere there.
>>686
nah arrogant retards make Windows great because they call you fat whenever you say you think it's bad. Which makes sense since only an arrogant person would dare to disagree with them.
>>684
>>685
>>686
>>690
why the fuck are you all being so obtuse?
>>677
a. Crash Course in C++
b. Learning D
c. say "fuck it!" (out loud) and learn a JVM language
D isn't broken vaporware. That's just a lot of the packages on dub.
depending on why you want to leave C, there might be other options.
>your actual Zig question
the language is almost completely undocumented. No proper language reference. No library reference. No "how the fuck does build.zig work" reference. It's all Zigguy's notes and reading existing code until it breaks.
So I've got no idea, dude. You can get going pretty quickly in Zig if you wrap C libraries and use simple constructs, but implementing a generic container is really asking for trouble.
Now I know javascript is a shit language, but I still wanna learn it. Using w3schools and it seems alright, but I feel there are better sites out there to help you learn. Any of you fags have any recommendations?
>>711
Mozilla Developer Network (MDN).
But really, anything explaining Javascript is shit. Surprisingly, not because the language is shit (well, it is, but not as much as people claim), but because the people involved in the feat are terrible.
That said, you can still get fairly far with w3schools, but if you don't start using something else as soon as possible you'll essentially write pajeet-level code forever.
>>712
>start using something else as soon as possible you'll essentially write pajeet-level code forever
Why is that? I know some of java's syntaxes are retarded, but otherwise why?
>>714
Some of w3schools's examples and explanations aren't exactly the best when it comes to the capabilities of the language(s).
On the other hand, it's a great site for when you don't remember something (e.g. the name of a built-in feature) and you need a quick reminder. It is certainly better organized than MDN.
>>715
Thanks anon, I'll keep that in mind.
Open file (8.58 KB 224x225 1566361594680.jpg)
>see random Perl merch for once
>text is "Perl's not dead"
>>711
https://eloquentjavascript.net/ worked for me. What it doesn't teach you, you don't need.
The problem with all JS materials is that they teach that you need semicolons in the language. The only difference between JS as practiced and Python-with-semicolons-on-every-line is that JS two places, neither common and one eliminated by nuJS lambda syntax, where you'd need a semicolon for disambiguation.
Open file (168.33 KB 496x323 ClipboardImage.png)
>>720
it would be a man this stylish, looking at me like I'm an idiot for suggesting that style matters.
>>719
Thanks, ill give it a look
>>719
Anyone who makes this big of a deal about fucking semicolons while having nothing else to say is a certified larper.
>>723
There's no other common problem with JS books. You read Eloquent JavaScript, You Don't Know JS, JavaScript: The Good Parts, literally the only pajeet thread is the entire community writing the language wrong due to superstition.
Maybe that other anon is talking about Sam's JavaScript in 21 Seconds-tier books. I'm talking about JS books you'd actually read.
>>8
i don't program at all, i just pretend i do to get my raise my nonexistent confidence in myself, i also am of the belief that programming is for beta cucks that let tyrone plow their wives/girlfirends/boyfriends(lol gay) and overall weakling faggots that only know how to code in order to sort the episodes of their anime collection.
>>697
>why you want to leave C
Because copying, pasting, and editing a bunch of code, writing a fuckton of
preprocessor macros, or using void* and a bunch of extra size/type variables
when all I want is a data structure feels niggerlicious.

>the language is almost completely undocumented.
Yeah, that's what I was hoping against. Guess I'm going to try D, then.
>>677
>>750
Just wait for Jai bro, compiler should be released around December 2027
>>719
What about regular Java?
>>775
what do you mean "regular Java"? Java is a completely different language.
>>777
I understand that, what I meant to ask is if you or that anon had a good book/pdf on Java. What he provided is pretty good.
>>780
The tutorials on Oracle's website are pretty good.
Also, if you read them you'll probably be better than your average Java pajeet.
>want to try D just for the heck of it
>they call dynamic array a "vector"
Nevermind.
>>787
that's a charming C++ism. Ignore that and focus on learning how good templates are, and how they're even better in D.
Currently researching on categorizing communities and cliques by topic and behavioral links within social media e.g. Twitter.
The papers "Detecting Community Kernels in Large Social Networks" and "A measure of polarization on social media Networks Based on community boundaries" gave me a few pointers as there are three types of users:
Those whose views are seen as important ("kernel"), those who mainly communicates with mostly the in-group ("internal" that are not "kernel"), and those who communicates mostly with the out-group ("boundary").
Here is the problem: The whole of Twitter is just a giant directed weighted graph due to follows, replies/quotes and retweets/likes, so there are different way of positively or negatively weight network edges.
>>794
this is the sexiest thing I have ever read. I bet all the women are jumping to get a chance at riding your dick
Open file (291.57 KB 1280x720 You're a nigger.webm)
>>794
>le tracking users meme
Terry disapproves.
Open file (25.45 KB 478x350 1kd2hi.jpg)
>>795
>>796
Here is the thing though, pic related. (Respect to Terry, RIP)
Originally I wanted to use this a as an antifa detector, but it will be versatile enough to do whatever social engineering tricks I want to do in the long run.
>>810
doesn't really matter. if you go down that path, you'll turn yourself into a literal commie, regardless of your intentions anon. use the innate social skills and spiritual insights God gave you, and stay away from trying to en-masse dox people. That's CIAnigger and SJW cuckoldry work.
>>811
I refuse to be a pacifist in this age of spiritual and cultural warfare. I refuse to be weak within a world full of commie animals.
There is a reason why Hitler had the idea of the Gestapo in the first place, because a Stasi is doomed to exist to fight the right.
To not fulfill the obligation of defending our own kind is evil, on the same level as Jordan B Peterson's neutering.
Hey /tech/, it's me again >>249 I have another programming question for you. I think I've made a mistake with this program but I can't see what I've done wrong specifically. Can you help me out with this.

<!DOCTYPE html>
<html>
<head>
<title>This Class</title>
<script type="text/javascript">
function changeText() {
document.getElementById("message").innerHTML=(Intro to Programming);
}
function clearText() {
document.getElementById("message").innerHTML=(<br>);
}
</script>
</head>
<body>
<div id="main">
<div id="header">
<h1>Final Exam 1 </h1>
</div>
<p id="demo">What is the name of this class?</p>
<p id="message"> <br> </p>
<button type="button" onClick="changeText()">Submit</button>
<button type="button" onClick="clearText()">Clear</button>
</div>
</body>
</html>
>>1024
Why did you place your strings within parentheses?
>>1025
Thanks for pointing out my error. I see what I did wrong.
>>1040
Thanks
Open file (437.65 KB 900x2134 1533338513112.jpg)
Open file (1.26 MB 865x1645 1533338716864.png)
Open file (2.57 MB 1534x1706 1533340705305.png)
Open file (1.49 MB 1134x2268 1490321001768.jpg)
>>1333 I don't know who made those images, but some of them are real niggerlicious. All you really need is TAoCP and SICP; then maybe a hardware book to understand cacheing. In particular, don't read these if you can't think critically yet, they will poison your mind: The Design of Everyday Things - An okay UX book, but only for GUI's or physical products; anything less falls short of Norman's ideals of affordances signifying actions. There's a lot to be said about designing command line tools or api's, and you can't apply the lessons from this book to those things, it'll end in disaster. Or worse, success. Design Patterns - Elements of Reusable Object Oriented Software - The book that's the foundation of much of our troubles today. It represents Object Oriented programming as an ideal instead of a paradigm that's sometimes useful. AbstractTextbookFactoryInterface, anyone? Also, Cathedral and Bazzar and Mythical Man Month are more about the meta-work of programming. They're about teamwork and human organizational structure. They're not bad, but they're not really programming books. There might be more, I haven't read all of them.
>>1334 > The email field is below the "More" instead of above the message like normal wtf lynx?
>>1334 So what kind of software have you programmed?
>>1336 Day-to-day I'm a DBA, occasionally I'll write external validation for the data in Lua, Python or Visual Basic; but the worst is when I have to update a Microsoft Access front-end.
dear /tech/ BO, would you mind reposting your code-block CSS? the newer site layout code seems to have broken my older version.
Is there any real reason to learn Lisp? From what little I understand of it, it seems to be more or less a more theoretical language, but not useful for practical programming.
>>1910 It teaches you in being methodical. Practical programming is not everything, some times you have to rid yourself of this "practicality" and reach a higher abstract layer: that way you can reach the purest form of programming and improve yourself. Lisp is not the absolute answer, but is a tool whose purpose is helping you reach the higher planes.
>>1910 It's an excellent tool for turning yourself into a pretentious stuck up douchebag who doesn't write actual software but still thinks he's on a higher plane of existence than actual programmers.
Open file (26.69 KB 469x313 r_1100259_csCdT.jpg)
SICP WAS A MISTAKE It's everything that was wrong with classic /tech/ >>1914 +1 upboat >>1913 -1 downboat
>>1903 Here it is. You could probably do better if you tried. code { white-space: pre; border: 1px double #00FF00; background: #000000; color: #00FF00; font-family: 'Lucida Console', Monaco, monospace; font-size: 105%; max-width: 100%; overflow: auto; padding: 1em 1.5em; display: block; word-wrap: break-word; } code br { display: block; }
>>1938 thanks bro, i'll give it a try.
I just discovered this interesting bit about C++20 Ranges watching Bjarne tonight: #include <iostream> #include <range/v3/view/span.hpp> using ranges::span; using std::cout; int main() { int a[128]{}; span s{a}; for (const auto x : s) { // a C-array can know it's own size now! cout << x << '\n'; } } span is a lightweight, non-mutating view of the underlying structure. https://en.cppreference.com/w/cpp/ranges
>>1953 heh, i guess it wouldn't hurt to point out where to get the ref implementation. C++20 has been voted in, but hasn't even been published yet afaik. here's eric neibler's library: https://github.com/ericniebler/range-v3
>>1953 >ranges actually, i just realized it's been separated out from under ranges in the official standard. https://en.cppreference.com/w/cpp/header/span
>>1953 >a C-array can know it's own size now! that's been the case since forever. all compilers I know resolve sizeof(myarray)/sizeof(*myarray) to a constant during compilation. #include <stdio.h> int main() { int a[128]; printf("items: %d\n", sizeof(a)/sizeof(*a)); //and a C for each loop for good measure. requires c99 because of scoped variables #define foreach(item, array) \ for(int keep = 1, \ count = 0,\ size = sizeof (array) / sizeof *(array); \ keep && count != size; \ keep = !keep, count++) \ for(item = (array) + count; keep; keep = !keep) foreach(int *i, a) *i = 3; int sum = 0; foreach(const int *i, a) sum += *i; printf("highest darts score: %x\n", sum); return 0; } what's new is you finally get a random-access iterator that supports all contiguous arrays: std::vector, std::array and c-arrays. like you ever need one. and you get a standardized wrapper for passing around bounded raw arrays, although you still need to check for yourself whether the array is still allocated.
>>1956 seems to me if that was the simple answer, then the C buffer overflow issue wouldn't be the number one security hole in the world for software. it's very hard to get it wrong from the looks of it using a C++ span to work with it. #include <cstdio> #include <range/v3/all.hpp> using ranges::span; int main() { int a[128]{}; span s{a}; printf("Hi, I'm a C-array of ints. My size is %li elements.\n", s.size()); }
>>1961 >seems to me if that was the simple answer, then the C buffer overflow issue wouldn't be the number one security hole in the world for software. In fact the sizeof trick works only on static arrays, i.e. those defined with [] and placed on the stack. Not only that, but it can't be used with arrays within structs or arrays passed to functions as arguments. There isn't a reliable way to prevent buffer overflows that is not modifying the core of the language.
>>1962 >but it can't be used with arrays within structs or arrays passed to functions as arguments. actually, views were explicitly designed for just this use-case. >There isn't a reliable way to prevent buffer overflows that is not modifying the core of the language. for C, sure. the point was how C++ is better. BTW, I don't think your output above is actually checking which is the highest score. Here's a better: #include <algorithm> #include <cstdio> #include <iterator> #include <range/v3/all.hpp> using ranges::span; using std::begin; using std::cbegin; using std::cend; using std::end; using std::generate; using std::max_element; int main() { int a[128]; span s{a}; generate(begin(s), end(s), [n = 1]() mutable { return n++ * 3; }); printf("highest darts score: %x\n", *max_element(cbegin(s), cend(s))); }
>>1963 >for C, sure. No shit, I was talking about C's arrays, not C++.
>>1964 Fair enough. But IMO C++ does C arrays much better than C does since 2011. C++20 will certainly amp that up a notch. #include <cstdio> #include <range/v3/all.hpp> using ranges::generate; using ranges::max_element; int main() { int a[128]; generate(a, [n = 0]() mutable { return ++n * 3; }); printf("highest darts score: %x\n", *max_element(a)); }
>>1963 >BTW, I don't think your output above is actually checking which is the highest score. lel, you should've run the program. what's the sum of 128 threes in hex? >>1965 >IMO C++ does C arrays much better than C does sure, but you shouldn't use raw arrays in c++ in the first place. std::array has the same constant length and compile-time properties, while also offering a bounds-checked ::at(n) and the right semantics for assigning and passing by value. hell, on review, span doesn't even do bounds checking. you have to check for yourself if index>0 && index<myspan.size(). yes, it's very hard to get out-of-bounds errors as long as you let the containers handle the ranges for you, like that foreach macro will keep you safe even in c. but once you do your own array[access] it's up to you because the library devs thought bounds checking costs too much performance. btw, buffer overflows are a different beast where you copy slabs of memory without checking if the data fits within the destination. Try #include <iostream> #include <algorithm> #include <array> using namespace std; int main() { array<char, 8> checked = {'C', 'h', 'e', 'c', 'k', 'e', 'd'}; cout << checked.data() << endl; array<char, 3> fun = {'F', 'u', 'n'}; copy(checked.cbegin()+3, checked.cend(), fun.begin()+2); cout << fun.data() << endl; checked.at(1) = 'i'; cout << checked.data() << endl; return 0; } both copy and << commit buffer overflow.
>>1967 >lel, you should've run the program i did in fact ofc. but you don't need to actually run the code to see that int sum = 0; foreach(const int *i, a) sum += *i; printf("highest darts score: %x\n", sum); isn't actually checking anything. it's simply exploiting the accidental artifact of the algorithm that the highest value was the last one set. max_element() OTOH, actually confirms the maximum value. >but you shouldn't use raw arrays in c++ in the first place. actually they are an absolute necessity in library code where they belong. the problems all come from having them in user code. ofc span doesn't do bounds-checking i said it was lightweight. it's hard to get it wrong if you use basic common sense and not intentionally trying to do it wrong. this certainly isn't the case with C arrays, where it's quite easy to fuck things up. Checked Fucked kid heh, very niggerlicious. neither are overflowing, copy is reallocating. try doing your trick with const std::array.
>>1971 >it's simply exploiting the accidental artifact of the algorithm that the highest value was the last one set. print your array and print mine and spot the difference. spoiler: mine is all threes, yours is 3,6..384. yes i'm actually summing the values like the variable name and the addition imply. >neither are overflowing, copy is reallocating try again. for example, print both arrays before and after with a foreach loop (print in hex to be extra sure you can see each character) and print their sizes and addresses. it may help you understand why the last line is "kid". hell, declare another array in between and see what happens.
>>1977 meh, intentionally creating a pathological case then saying "see your shit's fucked!" is disingenuous at best. when the standard says something is undefined, it's smartest not to go there, particularly when specific guidance is given regarding a necessity case. copy_backward(checked.cbegin() + 3, checked.cend(), fun.begin() + 2);
>>1979 you absolute braindead ape, the whole point of that code is to show a buffer overflow. of course that's a pathological case.
C++ newb askin. as i see it cbegin returns iterator, a type for iterating collection, right? Then how could compiler allow +3 on it. Isnt it better .next().next().next() or .skip(3). I wonder then if its possible to -3 on cbegin() lol I mean if i have compile-time created collection then compiler knows its size and could optimize away internal bounds checking. But for dynamically created (which i suppose more common) you will check lengh by hand either way, so automatic, embedded in iterator type bounds checker, sould not affect performance.
>>1985 Iterators are their own type as you implied. They support operators like many of the other types. The additive operators as well as Boolean ones. Best to think of them as pointers in the context of your question IMO (though they aren't brain-dead like raw pointers, but rather know what they are actually traversing). Here's an example of writing your own iterators & operators, maybe that will clear things up. https://en.cppreference.com/w/cpp/iterator/iterator >>1984 Funny, I noticed that when I followed the standard, your little contrivance fell apart.
Finally beginning to learn how to generate images using code. // filename: vector.cpp // sauce: https://raytracing.github.io/books/RayTracingInOneWeekend.html // this file is babby's first image generator // usage: ./build/vector > image.ppm #include <iostream> #include "Vec3.hpp" using std::cerr; using std::cout; int main() { const int image_width{200}; const int image_height{100}; cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; for (int j = image_height - 1; j >= 0; --j) { cerr << "\rScanlines remaining: " << j << ' ' << std::flush; for (int i = 0; i < image_width; ++i) { Vec3 color{double(i) / image_width, double(j) / image_height, 0.2}; color.write_color(cout); } } cerr << "\nDone.\n"; }
>>2300 >Vec3.hpp #pragma once #include <cmath> #include <iostream> class Vec3 { public: Vec3() : e{0, 0, 0} { } Vec3(double e0, double e1, double e2) : e{e0, e1, e2} { } // funcs double x() const { return e[0]; } double y() const { return e[1]; } double z() const { return e[2]; } Vec3 operator-() const { return Vec3(-e[0], -e[1], -e[2]); } double operator[](int i) const { return e[i]; } double& operator[](int i) { return e[i]; } Vec3& operator+=(const Vec3& v) { e[0] += v.e[0]; e[1] += v.e[1]; e[2] += v.e[2]; return *this; } Vec3& operator*=(const double t) { e[0] *= t; e[1] *= t; e[2] *= t; return *this; } Vec3& operator/=(const double t) { return *this *= 1 / t; } double length() const { return sqrt(length_squared()); } double length_squared() const { return e[0] * e[0] + e[1] * e[1] + e[2] * e[2]; } void write_color(std::ostream& out) { // Write the translated [0,255] value of each color component. out << static_cast<int>(255.999 * e[0]) << ' ' << static_cast<int>(255.999 * e[1]) << ' ' << static_cast<int>(255.999 * e[2]) << '\n'; } // fields double e[3]; }; // vec3 Utility Functions inline std::ostream& operator<<(std::ostream& out, const Vec3& v) { return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2]; } inline Vec3 operator+(const Vec3& u, const Vec3& v) { return Vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]); } inline Vec3 operator-(const Vec3& u, const Vec3& v) { return Vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]); } inline Vec3 operator*(const Vec3& u, const Vec3& v) { return Vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]); } inline Vec3 operator*(double t, const Vec3& v) { return Vec3(t * v.e[0], t * v.e[1], t * v.e[2]); } inline Vec3 operator*(const Vec3& v, double t) { return t * v; } inline Vec3 operator/(Vec3 v, double t) { return (1 / t) * v; } inline double dot(const Vec3& u, const Vec3& v) { return u.e[0] * v.e[0] + u.e[1] * v.e[1] + u.e[2] * v.e[2]; } inline Vec3 cross(const Vec3& u, const Vec3& v) { return Vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1], u.e[2] * v.e[0] - u.e[0] * v.e[2], u.e[0] * v.e[1] - u.e[1] * v.e[0]); } inline Vec3 unit_vector(Vec3 v) { return v / v.length(); }
>>2300 I think I have the conventional row & column matrix variable names backwards there. This should be more standard. // filename: vector.cpp // sauce: https://raytracing.github.io/books/RayTracingInOneWeekend.html // this file is babby's first image generator // usage: ./build/vector > image.ppm #include <iostream> #include "Vec3.hpp" using std::cerr; using std::cout; int main() { const int w{200}, h{100}; cout << "P3\n" << w << ' ' << h << "\n255\n"; for (int i{h - 1}; i >= 0; --i) { cerr << "\rScanlines remaining: " << i << ' ' << std::flush; for (int j{0}; j < w; ++j) { Vec3 pix{double(j) / w, double(i) / h, 0.2}; pix.write_colr(cout); } } cerr << "\nDone.\n"; }
Open file (5.83 KB 200x100 image.png)
Well I'm going to call it a day for now, but I wanted to show /tech/ my progress so far. It's nothing fancy yet, but it has real background gradient, raytracing, and surface normals. I've never understood the basic mechanics of how to do this kind of thing inside code before, but this guy is not only good at it, but he also explains things in an easy-to-understand way as you go along. Reading his code is pretty straightforward even if I don't understand all the maths yet. I'll post my code in the next one, & btw I don't know how to save files out in a format like .png yet, so I just converted it from .ppm in GIMP.
>ray1.cpp // filename: ray1.cpp // -this file is babby's first raycaster // sauce: // https://raytracing.github.io/books/RayTracingInOneWeekend.html // #rays,asimplecamera,andbackground #include <iostream> #include "Ray.hpp" using std::cerr; using std::cout; /**----------------------------------------------------------------------------- */ double hit_sphere(const Vec3& center, const double radius, const Ray& r) { Vec3 oc{r.origin() - center}; auto a{dot(r.dir(), r.dir())}; auto b{2.0 * dot(oc, r.dir())}; auto c{dot(oc, oc) - (radius * radius)}; auto dscrmnt{(b * b) - ((4 * a) * c)}; if (dscrmnt < 0) { return -1.0; } else { return (-b - sqrt(dscrmnt)) / (2.0 * a); } } /**----------------------------------------------------------------------------- The ray_color(ray) function linearly blends white and blue depending on the height of the y coordinate after scaling the ray direction to unit length (so −1.0 < y < 1.0). Because we're looking at the y height after normalizing the vector, you'll notice a horizontal gradient to the color in addition to the vertical gradient. */ Color ray_color(const Ray& r) { auto t{hit_sphere(Vec3{0, 0, -1}, 0.5, r)}; // The ray parameter t if (t > 0.0) { auto N{unit_vec(r.at(t) - Vec3{0, 0, -1})}; // surface normal return 0.5 * Color{N.x() + 1, N.y() + 1, N.z() + 1}; } auto unit_dir{unit_vec(r.dir())}; t = 0.5 * (unit_dir.y() + 1.0); // 0.0 ≤ t ≤ 1.0 return ((1.0 - t) * Vec3{1.0, 1.0, 1.0}) + (t * Color{0.5, 0.7, 1.0}); } /**----------------------------------------------------------------------------- */ int main() { const int w{200}, h{100}; cout << "P3\n" << w << " " << h << "\n255\n"; Vec3 lwr_lt{-2.0, -1.0, -1.0}; Vec3 horz{4.0, 0.0, 0.0}; Vec3 vtcl{0.0, 2.0, 0.0}; Vec3 origin{0.0, 0.0, 0.0}; // cam origin for (int i{h - 1}; i >= 0; --i) { cerr << "\rScanlines remaining: " << i << ' ' << std::flush; for (int j{0}; j < w; ++j) { auto u{double(j) / w}; // [0 - 1) auto v{double(i) / h}; // " // 4 Vec3's are used here to construct the ray: // 1 standalone, then 3 added together after two multiplied by uv doubles // r = (Vec3, (Vec3 + Vec3 + Vec3)) Ray r{origin, lwr_lt + (horz * u) + (vtcl * v)}; Color pix{ray_color(r)}; pix.wrt_colr(cout); } } cerr << "\nDone.\n"; } >Ray.hpp #pragma once #include "Vec3.hpp" class Ray { public: Ray() {} Ray(const Vec3& origin, const Vec3& dir) : origin_{origin} , dir_{dir} {} // funcs Vec3 origin() const { return origin_; } Vec3 dir() const { return dir_; } // p(t) = a + tb Vec3 at(const double t) const { return origin_ + (t * dir_); } // fields Vec3 origin_; Vec3 dir_; }; And, other than some cleanups, I added this using directive towards the bottom of Vec3.hpp, since color is so often stored inside a vec3. > // since it's such a common use-case, we'll create a color alias from the vec3 using Color = Vec3; Have a good one, /tech/.
I should have added a usage comment in ray1.cpp > // usage: ./build/ray1 > image.ppm
sepples is such a beautiful language
I decided that defining a Sphere type and using it clarifies the intent further: > struct Sphere { Vec3 center; double radius; }; >usage in ray_color() Color ray_color(const Ray& r) { Sphere s{Vec3{0, 0, -1}, 0.5}; auto t{hit_sphere(r, s)}; // The ray parameter t >usage in hit_sphere() double hit_sphere(const Ray& r, const Sphere& s) { Vec3 oc{r.origin() - s.center}; auto a{dot(r.dir(), r.dir())}; auto b{2.0 * dot(oc, r.dir())}; auto c{dot(oc, oc) - (s.radius * s.radius)}; >>2310 I agree. I can take some getting used to if you come from C as I did, and it's even morejust as prone to the same type of abuse. But it can be used correctly and it's a pleasure to work with when it is.
Open file (5.22 KB 200x100 image.png)
Welp, got more work done today. During the next part of the code design, he abstracts the notion of 'Hittable' so that the raycast hit function can apply to any arbitrary things and not just be hard-coded into the function. He creates a 'Hittable' abstract class, then a 'Hittable_list' that encapsulates a std::vector of Hittable's. He apparently agreed with me that abstracting the idea of a Sphere itself was a good idea (also derived from Hittable, ofc), and created a couple of constants and functions in a Utility file. Finally he ties everything back together in the original main file, adding a couple of spheres into the world, and it both simplifies the code overall and to my way of thinking pretty much makes the entire thing easier to reason about. Here's the fruits of all my toil today haha. :^) > I'll add the code in the next post. Have a good one /tech/.
>Utility.hpp #pragma once // headers #include <cmath> #include <cstdlib> #include <iostream> #include <limits> #include <memory> #include <vector> #include "Ray.hpp" #include "Vec3.hpp" // usings using std::cerr; using std::cout; using std::make_shared; using std::shared_ptr; using std::vector; // constants const double inf = std::numeric_limits<double>::infinity(); const double pi = 3.1415926535897932385; // functions inline double deg_to_rad(const double deg) { return (deg * pi) / 180.0; } inline double ffmin(const double a, const double b) { return a <= b ? a : b; } inline double ffmax(const double a, const double b) { return a >= b ? a : b; } >Hittable.hpp #pragma once #include "Utility.hpp" struct Hit_rec { double t; Vec3 p; Vec3 normal; bool front_face; // we're using the geo approach and just having normals always face outwards inline void set_normal(const Ray& r, const Vec3& out_normal) { front_face = dot(r.dir(), out_normal) < 0; // is normal in same dir as ray? normal = front_face ? out_normal : -out_normal; } }; /**----------------------------------------------------------------------------- "...a very clean solution is the make an “abstract class” for anything a ray might hit and make both a sphere and a list of spheres just something you can hit. What that class should be called is something of a quandary — calling it an “object” would be good if not for “object oriented” programming. “Surface” is often used, with the weakness being maybe we will want volumes. “hittable” emphasizes the member function that unites them. I don’t love any of these but I will go with “hittable”. */ class Hittable { public: virtual bool hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const = 0; }; >Hittable_list.hpp #pragma once #include "Hittable.hpp" #include "Utility.hpp" /**----------------------------------------------------------------------------- */ class Hittable_list : public Hittable { public: Hittable_list() {} Hittable_list(shared_ptr<Hittable> obj) { add(obj); } // funcs void clear() { objs.clear(); } void add(shared_ptr<Hittable> obj) { objs.push_back(obj); } virtual bool hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const override; // fields vector<shared_ptr<Hittable>> objs; }; /**----------------------------------------------------------------------------- */ bool Hittable_list::hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const { Hit_rec tmp_rec{}; bool have_hit{false}; auto closest{t_max}; // we only need to be concerned w/ closest normal for (const auto& obj : objs) { if (obj->hit(r, t_min, closest, tmp_rec)) { have_hit = true; closest = tmp_rec.t; // set during obj.hit() rec = tmp_rec; } } return have_hit; } >Sphere.hpp #pragma once #include "Hittable.hpp" /**----------------------------------------------------------------------------- */ class Sphere : public Hittable { public: Sphere() {} Sphere(const Vec3& center, const double radius) : center_{center} , radius_{radius} {} virtual bool hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const override; bool set_normal(const Ray& r, Hit_rec& rec, const double tmp) const; // fields Vec3 center_; double radius_; }; /**----------------------------------------------------------------------------- */ bool Sphere::hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const { Vec3 oc{r.origin() - center_}; auto a{r.dir().len_squared()}; auto half_b{dot(oc, r.dir())}; auto c{oc.len_squared() - (radius_ * radius_)}; auto dscrmnt{(half_b * half_b) - (a * c)}; if (dscrmnt > 0.0) { auto root{sqrt(dscrmnt)}; auto tmp{(-half_b - root) / a}; if (tmp > t_min && tmp < t_max) return set_normal(r, rec, tmp); // let's try it from the other side then tmp = (-half_b + root) / a; if (tmp > t_min && tmp < t_max) return set_normal(r, rec, tmp); } return false; } /**----------------------------------------------------------------------------- */ bool Sphere::set_normal(const Ray& r, Hit_rec& rec, const double tmp) const { rec.t = tmp; rec.p = r.at(rec.t); auto out_normal{(rec.p - center_) / radius_}; rec.set_normal(r, out_normal); return true; }
I'll go ahead and repost ray1.cpp as well, since it's changed a fair bit now (for the better imo). > // filename: ray1.cpp // -this file is babby's first raycaster // usage: ./build/ray1 > image.ppm // // sauce: // https://raytracing.github.io/books/RayTracingInOneWeekend.html // #rays,asimplecamera,andbackground #include "Hittable_list.hpp" #include "Sphere.hpp" #include "Utility.hpp" /**----------------------------------------------------------------------------- */ Color ray_color(const Ray& r, const Hittable& world) { // calc any raycast hits in the world Hit_rec rec{}; if (world.hit(r, 0.0, inf, rec)) return 0.5 * (rec.normal + Color{1.0, 1.0, 1.0}); // otherwise, do background gradient... /* The ray_color(ray) function linearly blends white and blue depending on the height of the y coordinate after scaling the ray direction to unit length (so −1.0 < y < 1.0). Because we're looking at the y height after normalizing the vector, you'll notice a horizontal gradient to the color in addition to the vertical gradient. */ auto unit_dir{unit_vec(r.dir())}; auto t{0.5 * (unit_dir.y() + 1.0)}; return ((1.0 - t) * Color{1.0, 1.0, 1.0}) + (t * Color{0.5, 0.7, 1.0}); } /**----------------------------------------------------------------------------- */ int main() { const int w{200}, h{100}; cout << "P3\n" << w << " " << h << "\n255\n"; Vec3 lwr_lt{-2.0, -1.0, -1.0}; Vec3 horz{4.0, 0.0, 0.0}; Vec3 vtcl{0.0, 2.0, 0.0}; Vec3 origin{0.0, 0.0, 0.0}; // cam origin // add a couple of spheres to the world Hittable_list world; world.add(make_shared<Sphere>(Vec3{0.0, 0.0, -1.0}, 0.5)); world.add(make_shared<Sphere>(Vec3{0.0, -100.5, -1.0}, 100.0)); // big one! for (int i{h - 1}; i >= 0; --i) { cerr << "\rScanlines remaining: " << i << ' ' << std::flush; for (int j{0}; j < w; ++j) { auto u{double(j) / w}; // [0 - 1) auto v{double(i) / h}; // " // 4 Vec3's are used here to construct the ray: // 1 standalone, then 3 added together after two multiplied by uv doubles // r = (Vec3, (Vec3 + Vec3 + Vec3)) Ray r{origin, lwr_lt + (horz * u) + (vtcl * v)}; Color pix{ray_color(r, world)}; pix.wrt_colr(cout); } } cerr << "\nDone.\n"; }
Added a Camera class and antialiasing today. > This significantly increased the run time since every pixel is now having 100 random rays cast into it (or is it 10'000?). I imagine there's a way to only perform the antialiasing along the edges of an object, but I'm not sure how to just yet. Anyway, he added a Camera class and moved the frame's settings into it's default ctor. He added random number generator which I tweaked to give a more random distribution between 0.0 and < 1.0 . The main() function now has a new Camera instance, and an interior loops that creates and sums the random rays for each pixel. ray_color() is unchanged.
>Camera.hpp #pragma once #include "Utility.hpp" class Camera { public: Camera() : origin{0.0, 0.0, 0.0} , lwr_lt{-2.0, -1.0, -1.0} , horz{4.0, 0.0, 0.0} , vtcl{0.0, 2.0, 0.0} {} // funcs inline Ray get_ray(const double u, const double v) const { return Ray{origin, lwr_lt + (u * horz) + (v * vtcl) - origin}; } // fields Vec3 origin; Vec3 lwr_lt; Vec3 horz; Vec3 vtcl; }; >Vec3.hpp snippet void wrt_colr(std::ostream& out, const int samps_per_pix) { auto scale{1.0 / samps_per_pix}; auto r{scale * e[0]}; auto g{scale * e[1]}; auto b{scale * e[2]}; // write out the normalized [0,255] value of each color component out << static_cast<int>(256 * std::clamp(r, 0.0, 0.999)) << ' ' << static_cast<int>(256 * std::clamp(g, 0.0, 0.999)) << ' ' << static_cast<int>(256 * std::clamp(b, 0.0, 0.999)) << '\n'; } >Utility.hpp snippets #include <functional> #include <random> using std::random_device; using unfrm_real_dstrb = std::uniform_real_distribution<double>; using dbl_func = std::function<double()>; // 0 ≤ r < 1 inline double rnd_double() { static unfrm_real_dstrb dstrb_0_1{0.0, 1.0}; static std::mt19937 rd_gen{random_device{}()}; static dbl_func rand_generator{bind(dstrb_0_1, rd_gen)}; return rand_generator(); }
>ray1.cpp snippet int main() { const int w{200}, h{100}; const int samps_per_pix{100}; cout << "P3\n" << w << " " << h << "\n255\n"; // add a couple of spheres into the world Hittable_list world{}; world.add(make_shared<Sphere>(Vec3{0.0, 0.0, -1.0}, 0.5)); world.add(make_shared<Sphere>(Vec3{0.0, -100.5, -1.0}, 100.0)); // big one! Camera cam{}; for (int i{h - 1}; i >= 0; --i) { cerr << "\rScanlines remaining: " << i << ' ' << std::flush; for (int j{0}; j < w; ++j) { Color pix{}; for (int s{0}; s < samps_per_pix; ++s) { auto u{(j + rnd_double()) / w}; auto v{(i + rnd_double()) / h}; Ray r{cam.get_ray(u, v)}; pix += ray_color(r, world); } pix.wrt_colr(cout, samps_per_pix); } } cerr << "\nDone.\n"; }
>>2354 forgot to add the std::bind include to the 1st Utilty.hpp snippet. > using std::bind;
>>2357 Actually, check that. It's 100, just like the variable names says. There are 200 random values between [0 - 1) for each pixel. (100 u, 100 v)
>>2358 Whuups! Time to change my diaper!
Open file (11.33 KB 200x100 image.png)
Began adding materials, starting with diffuse Lambert. > He added three variations of scattering functions for the rays, and made ray_color() recursive now, with a bounce-limit parameter. He also added a gamma-correction of 2 to the wrt_colr() func in Vec3.
>ray1.cpp snippets Color ray_color(const Ray& r, const Hittable& world, const int depth) { // calc any raycast hits in the world if (depth <= 0) return Vec3{0.0, 0.0, 0.0}; // at bounce limit, gather stops // the recursion will stop once we fail to hit anything Hit_rec rec{}; if (world.hit(r, 0.001, inf, rec)) { // epsilon used to rm shadow-acne // try these variations // Vec3 targ{rec.p + rec.normal + rnd_unit_vec()}; // Vec3 targ{rec.p + rec.normal + rnd_in_unit_sphere()}; Vec3 targ{rec.p + rec.normal + rnd_in_hemi(rec.normal)}; // recursive return 0.5 * ray_color(Ray{rec.p, targ - rec.p}, world, depth - 1); } int main() { const int w{200}, h{100}; const int samps_per_pix{100}; const int max_bounce{50}; ... pix += ray_color(r, world, max_bounce); >Vec3.hpp snippets void wrt_colr(std::ostream& out, const int samps_per_pix) { auto scale{1.0 / samps_per_pix}; // add gamma-correction 2.0 auto r{sqrt(scale * e[0])}; auto g{sqrt(scale * e[1])}; auto b{sqrt(scale * e[2])}; // unit length Vec3 rnd_unit_vec() { auto a{rnd_double(0.0, pi)}; auto z{rnd_double(-1.0, 1.0)}; auto r{sqrt(1.0 - (z * z))}; return Vec3{r * cos(a), r * sin(a), z}; } // random length [0 - 1) Vec3 rnd_in_unit_sphere() { while (true) { auto p{Vec3::random(-1.0, 1.0)}; if (p.len_squared() >= 1.0) // this effectively limits the 2.0 range continue; // [-1 - 1) above down to just unit length return p; } } // half volume Vec3 rnd_in_hemi(const Vec3& normal) { Vec3 in_unit_sphere{rnd_in_unit_sphere()}; if (dot(in_unit_sphere, normal) > 0.0) return in_unit_sphere; else return -in_unit_sphere; } >Utility.hpp snippet inline double rnd_double(const double min, const double max) { static unfrm_real_dstrb dstrb_0_1{min, max}; static std::mt19937 rd_gen{random_device{}()}; static dbl_func rand_generator{bind(dstrb_0_1, rd_gen)}; return rand_generator(); } inline double rnd_double() { return rnd_double(0.0, 1.0); // 0 ≤ r < 1 } I think that'll do for today, I'll plan to start chapter 9 tomorrow. Cheers.
>>2361 Just realized my random double function's var name needed adjusting after the params change. inline double rnd_double(const double min, const double max) { static unfrm_real_dstrb dstrb_min_max{min, max}; static std::mt19937 rd_gen{random_device{}()}; static dbl_func rand_generator{bind(dstrb_min_max, rd_gen)}; return rand_generator(); }
>>2362 >static unfrm_real_dstrb dstrb_min_max{min, max}; Won't this cause only the first function call to set min/max? Wouldn't the function use the values from the first function call afterwards due to "static"? C++ doesn't have parameter-based memoization AFAIK.
>>2363 easy enough to test anon, judge for yourself. #include <functional> #include <iostream> #include <random> using std::random_device; using unfrm_real_dstrb = std::uniform_real_distribution<double>; using dbl_func = std::function<double()>; inline double rnd_double(const double min, const double max) { static unfrm_real_dstrb dstrb_min_max{min, max}; static std::mt19937 rd_gen{random_device{}()}; static dbl_func rand_generator{bind(dstrb_min_max, rd_gen)}; return rand_generator(); } int main() { for (unsigned i{0}; i < 10; ++i) { std::cout << rnd_double(0.0, 1.0) << ' '; } std::cout << "\n\n"; } output example: 0.165246 0.4991 0.579882 0.213314 0.603315 0.565854 0.268919 0.708031 0.586541 0.368085
>>2363 my first experiments seem to prove your point given my simple test harness. near as i can tell however, this code worked correctly (at least a first glance) // unit length Vec3 rnd_unit_vec() { auto a{rnd_double(0.0, pi)}; auto z{rnd_double(-1.0, 1.0)}; auto r{sqrt(1.0 - (z * z))}; return Vec3{r * cos(a), r * sin(a), z}; } thanks for the query anon, i'll look into it further tomorrow.
>>2364 this is the loop i should have written here: for (unsigned i{0}; i < 10; ++i) { std::cout << rnd_double(0.0, double(i)) << ' '; }
Open file (13.88 KB 200x100 cpp_image_mins.png)
Open file (13.84 KB 200x100 c_image_secs.png)
>>2363 OK, I've both confirmed your point, and also discovered why that approach was taken, most likely. I thought it odd that the shadows seemed to have an angle. Sure enough seemingly it's because the min/max was locked in on the first use. Fixing it by removing the statics fixed it, but dramatically increased the rendering time as well. I tweaked it for slightly better performance but in the end switched over to a C version. >Utiltiy.hpp #pragma once #include <algorithm> #include <cmath> #include <cstdlib> #include <iostream> #include <limits> #include <memory> #include <vector> // usings using std::cerr; using std::cout; using std::make_shared; using std::shared_ptr; using std::vector; // constants const double inf{std::numeric_limits<double>::infinity()}; const double pi{3.1415926535897932385}; // functions inline double rnd_double() { // Returns a random real in [0,1). return rand() / (RAND_MAX + 1.0); } inline double rnd_double(double min, double max) { // Returns a random real in [min,max). return min + (max - min) * rnd_double(); } inline double deg_to_rad(const double deg) { return (deg * pi) / 180.0; } inline double ffmin(const double a, const double b) { return a <= b ? a : b; } inline double ffmax(const double a, const double b) { return a >= b ? a : b; } // headers (include here at the end) #include "Ray.hpp" #include "Vec3.hpp" This is now back to rendering in just seconds. I think the C++ version is a tiny bit better quality (to my admittedly untrained eye) but the increase in rendering time simply isn't worth it. The C version is plenty good enough. > He implied as much in the text of the book that it wasn't an optimal solution on the standard C++ library's part in the case of their random number generator. There are few areas where C is still notably superior to C++ (I've coded in both professionally for years), but cleary the random number generator system is an area that is still inferior in the C++ system.
>>2371 > but cleary the random number generator system is an area that is still inferior in the C++ system. I guess that was a bit hasty. In all fairness to the C++ set of random number libraries, they are a) far more flexible & extensive, b) able to easily be tweaked in algorithms by simply swapping in differing engines & distributions, etc. c) preferred in the sciences & maths in general over the C version for just these reasons, and finally far more extensively developed into new alternatives version after version of the standard. The slower runtime is probably a direct artifact of the much more careful attention to accuracy in the case of these engines. linear_congruential_engine minstd_rand0(C++11) minstd_rand(C++11) mersenne_twister_engine mt19937(C++11) mt19937_64(C++11) subtract_with_carry_engine ranlux24_base(C++11) ranlux48_base(C++11) discard_block_engine ranlux24(C++11) ranlux48(C++11) independent_bits_engine shuffle_order_engine knuth_b(C++11) non-deterministic random number generator using hardware entropy source Uniform distributions uniform_real_distribution Bernoulli distributions bernoulli_distribution uniform_int_distribution binomial_distribution negative_binomial_distribution geometric_distribution Poisson distributions poisson_distribution exponential_distribution gamma_distribution weibull_distribution extreme_value_distribution Normal distributions normal_distribution lognormal_distribution chi_squared_distribution cauchy_distribution fisher_f_distribution student_t_distribution Sampling distributions discrete_distribution piecewise_constant_distribution piecewise_linear_distribution Utilities generate_canonical seed_seq > https://en.cppreference.com/w/cpp/header/random With C, you get rand() love it or leave it. In much of engineering the C version may suffice and certainly in the case of a raytracer. But for actual accuracy in the maths & sciences, the C++ version is far superior.
>>2353 BTW, I discovered I inadvertently had smoothing during zoom turned on in my image viewer for the earlier cap. Here's an actual-accurate rendition of what the anti-aliasing is doing in the algorithm.
>>2373 >and finally [d)] far more extensively developed into new alternatives version after version of the standard. I guess I should have clarified that it's the entire sweep of the numerics libraries that are constantly being updated each iteration of the standard, since that's really what I meant. https://en.cppreference.com/w/cpp/numeric C++ has firmly established itself as an important software framework for scientific investigation over the last decade, and underlies much of the advances in scripting frameworks in languages like Python & R, for example TensorFlow.
Open file (19.74 KB 200x100 image.png)
OK, began working on metals and reflections now. He created a Materials abstract class that has a scatter() function. Then two classes that inherit from it; a Lambertian class that moves the previous behavior from the ray_color() function in, and also a Metal class that has reflectivity. The hit record struct now has a Material shared pointer field now, and a couple of new metal spheres were added into the scene. > It's apparent the Camera field settings could use some tweaking, but the system has real metal reflections now so that feels pretty neat tbh.
>Material.hpp #pragma once #include "Hittable.hpp" #include "Utility.hpp" /**----------------------------------------------------------------------------- */ class Material { public: virtual bool scatter(const Ray& ray_in, const Hit_rec& rec, Vec3& attenuation, Ray& scattered) const = 0; }; /**----------------------------------------------------------------------------- */ class Lambertian : public Material { public: Lambertian(const Vec3& albedo) : albedo_{albedo} {} virtual bool scatter(const Ray& /*ray_in*/, const Hit_rec& rec, Vec3& attenuation, Ray& scattered) const override { // Vec3 scatter_dir{rec.normal + rnd_unit_vec()}; // Vec3 scatter_dir{rec.normal + rnd_in_unit_sphere()}; Vec3 scatter_dir{rec.normal + rnd_in_hemi(rec.normal)}; scattered = Ray{rec.p, scatter_dir}; attenuation = albedo_; return true; } // fields Vec3 albedo_; }; /**----------------------------------------------------------------------------- */ class Metal : public Material { public: Metal(const Vec3& albedo) : albedo_{albedo} {} virtual bool scatter(const Ray& ray_in, const Hit_rec& rec, Vec3& attenuation, Ray& scattered) const override { Vec3 reflected{reflect(unit_vec(ray_in.dir()), rec.normal)}; scattered = Ray{rec.p, reflected}; attenuation = albedo_; return dot(scattered.dir(), rec.normal) > 0.0; } // fields Vec3 albedo_; }; >Hittable.hpp snippet class Material; struct Hit_rec { Vec3 p; Vec3 normal; bool front_face; double t; shared_ptr<Material> mat_p; // we're using the geo approach and just having normals always face outwards inline void set_normal(const Ray& r, const Vec3& out_normal) { front_face = dot(r.dir(), out_normal) < 0; // is normal in same dir as ray? normal = front_face ? out_normal : -out_normal; } }; >Sphere.hpp snippet /**----------------------------------------------------------------------------- */ class Sphere : public Hittable { public: Sphere() {} Sphere(const Vec3& center, const double radius, shared_ptr<Material> mat_p) : center_{center} , radius_{radius} , mat_p_{mat_p} {} virtual bool hit(const Ray& r, const double t_min, const double t_max, Hit_rec& rec) const override; bool set_normal(const Ray& r, Hit_rec& rec, const double tmp) const; // fields Vec3 center_; double radius_; shared_ptr<Material> mat_p_; }; >Vec3.hpp snippet inline Vec3 reflect(const Vec3& v, const Vec3& n) { return v - ((2 * dot(v, n)) * n); }
ray_color() is still recursive, but is simpler now. the objects need to be constructed with a material pointer now. >ray1.cpp // filename: ray1.cpp // -this file is babby's first raycaster // usage: ./build/ray1 > image.ppm // // sauce: // https://raytracing.github.io/books/RayTracingInOneWeekend.html #include "Camera.hpp" #include "Hittable_list.hpp" #include "Material.hpp" #include "Sphere.hpp" /**----------------------------------------------------------------------------- */ Color ray_color(const Ray& r, const Hittable& world, const int depth) { // calc any raycast hits in the world if (depth <= 0) return Vec3{0.0, 0.0, 0.0}; // at bounce limit, gather stops // the recursion will stop once we fail to hit anything Hit_rec rec{}; if (world.hit(r, 0.001, inf, rec)) { // epsilon used to rm shadow-acne Ray scattered{}; Vec3 attenuation{}; // recursive if (rec.mat_p->scatter(r, rec, attenuation, scattered)) return attenuation * ray_color(scattered, world, depth - 1); return Vec3{0.0, 0.0, 0.0}; } // otherwise, do background gradient... auto unit_dir{unit_vec(r.dir())}; auto t{0.5 * (unit_dir.y() + 1.0)}; return ((1.0 - t) * Color{1.0, 1.0, 1.0}) + (t * Color{0.5, 0.7, 1.0}); } /**----------------------------------------------------------------------------- */ int main() { const int w{200}, h{100}; const int samps_per_pix{100}; const int max_bounce{50}; cout << "P3\n" << w << " " << h << "\n255\n"; // add some spheres into the world Hittable_list world{}; world.add(make_shared<Sphere>(Vec3{0, 0, -1}, 0.5, make_shared<Lambertian>(Color{0.5, 0.7, 1.0}))); world.add(make_shared<Sphere>(Vec3{0, -100.5, -1}, 100, make_shared<Lambertian>(Color{0.8, 0.8, 0.8}))); world.add(make_shared<Sphere>(Vec3{1, 0, -1}, 0.5, make_shared<Metal>(Color{0.8, 0.6, 0.2}))); world.add(make_shared<Sphere>(Vec3{-1, 0, -1}, 0.5, make_shared<Metal>(Color{0.7, 0.5, 0.8}))); // Camera cam{}; for (int i{h - 1}; i >= 0; --i) { cerr << "\rScanlines remaining: " << i << ' ' << std::flush; for (int j{0}; j < w; ++j) { Color pix{}; for (int s{0}; s < samps_per_pix; ++s) { auto u{(j + rnd_double()) / w}; auto v{(i + rnd_double()) / h}; Ray r{cam.get_ray(u, v)}; pix += ray_color(r, world, max_bounce); } pix.wrt_colr(cout, samps_per_pix); } } cerr << "\nDone.\n"; }
>>2452 He added a 'fuzz' parameter to the Metal ctor that can diffuse the reflectivity making it appear somewhat like cast or brushed metal. This example uses a ~1/3 setting. > >Material.hpp snippet /**----------------------------------------------------------------------------- */ class Metal : public Material { public: Metal(const Color& albedo, double fuzz = 0.0) : albedo_{albedo} , fuzz_{fuzz < 1.0 ? fuzz : 1.0} {} // virtual bool scatter(const Ray& ray_in, const Hit_rec& rec, Color& attenuation, Ray& scattered) const override { Vec3 reflected{reflect(unit_vec(ray_in.dir()), rec.normal)}; scattered = Ray{rec.p, reflected + (fuzz_ * rnd_in_unit_sphere())}; attenuation = albedo_; return dot(scattered.dir(), rec.normal) > 0.0; } // Color albedo_; double fuzz_; }; >ray1.cpp snippet /**----------------------------------------------------------------------------- */ void add_objs_to(Hittable_list& world) { // add some spheres into the world // Lamberts world.add(make_shared<Sphere>(Vec3{0.0, 0.0, -1.0}, 0.5, make_shared<Lambertian>(Color{0.5, 0.7, 1.0}))); world.add(make_shared<Sphere>(Vec3{0.0, -100.5, -1.0}, 100.0, make_shared<Lambertian>(Color{0.8, 0.8, 0.8}))); // Metals world.add(make_shared<Sphere>(Vec3{1.0, 0.0, -1.0}, 0.5, make_shared<Metal>(Color{0.8, 0.6, 0.2}, 0.3))); world.add(make_shared<Sphere>(Vec3{-1.0, 0.0, -1.0}, 0.5, make_shared<Metal>(Color{0.7, 0.5, 0.8}))); } /**----------------------------------------------------------------------------- */ int main() { const int w{200}, h{100}; const int samps_per_pix{100}; const int max_bounce{50}; cout << "P3\n" << w << " " << h << "\n255\n"; Hittable_list world{}; add_objs_to(world); Camera cam{}; ...
Open file (20.67 KB 200x100 image.png)
>>2456 forgot example pic
Hi gommie! :^)
Open file (50.44 KB 604x551 1427818685578.jpg)
>>2476 Hello Robot.
>finally figured out what pointer arithmetic is useful for
>>2959 Seems to me there are numerous uses for pointer arithmetic (and an even larger set of potential abuses of them). Mind spelling out what you realized Anon?
>>2959 >>2960 >useful for what >\0 What mean?
>>2961 >What mean? > start here for the answers to these and other deep mysteries anon.
Open file (89.68 KB 786x1017 DAY OF THE SEAL.jpg)
>What are you working on? DAY OF THE SEAL
>>2963 Silly Anon, DAY OF THE POLAR BEAR is coming soon tbh.
>>2962 Don't be mean. Every beginner need pointers. >>2961 >>0 Here you go.
>>2968 > Every beginner need pointers. < badumtiss >>0 < le ebin rusemaster
>>2970 In most implementation, NULL == 0
>>2974 yes, but macros are evil tbh. use nullptr if you need a NULL. otherwise just use an int, but definitely don't treat pointers like integers.
>>2978 >don't treat pointers like integers heh, https://godbolt.org/z/LcpGg-
Open file (46.78 KB 610x402 Top.Men.jpeg)
>>2979 >uses compiler explorer < mein dude >top-quality code < pic related I'm conflicted here, Anon.
Open file (346.74 KB 751x1100 1561259958667.png)
>What are you working on? A program that slightly "simulates" various models of soviet built reaktor and turbine models, that uses fugtorio power calculation formula because I'm a fucking math pleb. Here is the picture code: https://0bin.net/paste/DrsKKzyJH7upJPvK#2pjTt1aQGNyVijAUt6ZS8pRHKBecYNnV31WD2gTxaQ4 when the code is more mature I will upload it on gitgud instead, currently I'm trying to hammer down the functionalities of the reaktors and turbines which are working in my opinion a little bit sub-optimal. The main issue is mostly that I can't get a way to work where there is diminishing returns when there is too many turbines running for example. Later I will try to write a parser so that the list of available models are saved in a text file so when I write the mainloop again the player can choose what types he wants to use in a structure/block.
>>2982 >The main issue is mostly that I can't get a way to work where there is diminishing returns when there is too many turbines running for example. I don't really into Python, but algorithmically-speaking, could you just sort of kludge a 'dim_returns' inverse power factor that would increase as the count of reactors went up? Regardless, looks interesting Anon.
>>2984 >I don't really into Python, but algorithmically-speaking, could you just sort of kludge a 'dim_returns' inverse power factor that would increase as the count of reactors went up? I just tinkered around with it now and I think the results of it should be sufficient for now, eh I think the code could be made a bit more compact asides from that it seems to be doing what I want, so what the code does is that it increase the power value with its initial value and for each run the divider and turbine count is incremented by 1, once the turbine count hits a threshold the divider kicks and the power increase is reduced. I could also make it so that there is a divider limit so that it doesn't reduce the power too much. Hmm, it does make me a bit curios if it will have a different behavior when I bother adding a water/steam flowrate object, I guess I will see it later once the reaktor/turbine object is more complete. """ Excepted pattern: 0 - 10 | + 0 1 - 20 | + 10 2 - 30 | + 10 -Start of diminishing return. 3 - 35 | + 5 4 - 38 | + 3 5 - 40.5 | + 2.5 """ init = 10 power = 0 div = 1 count_t = 0 def start(): global power, init, div, count_t calc = 0 if count_t <= 3: calc += init power += calc elif count_t > 3: calc = init / div power += calc print("Add:", round(calc, 2), "Power:", round(power, 2)) for i in range(10): div += 0.25 count_t += 1 start() >Regardless, looks interesting Anon. Thanks.
>>2985 Yea that seems like it would work ok.
>>2981 > >top-quality code but it is! it gives the right output in the console! it's basically 5 demos of pointer abuse crammed into one file: 1. abusing local variable addresses to find out call depth 2. abusing function addresses to calculate other function addresses 3. abusing stack-allocated null-terminated strings to build a longer string 4. abusing the fact that array[i] is the same as i[array] and *(array+i). though, is it really abuse when the compiler specifically allows these notations as long as exactly 1 identifier is a pointer? also using the most horrid syntax to increment a value to the left: ++*--p 5. abusing zero-length arrays just for type info and abusing nested VLAs to perform multiplication. it's not really pointer abuse, but it's related because it takes a pointer difference between the start and end of a VLA for a calculation not included is demo 6: changing a function pointer with arguments A to a function pointer taking arguments B and calling it. also not included is demo 7: fun with pointers in printf https://github.com/carlini/printf-tac-toe
>>2985 if you want a simple formula for diminishing returns with a given maximum, it's: power = max_power*turbine_count/(turbine_count-1+max_power/power_per_turbine) (you can check for yourself that with 0 turbines you get power=0, with 1 turbine it's power=power_per_turbine and with infinite turbines it's power=max_power) if you get multiple types of turbines hooked up to the same system, you can calculate an average power_per_turbine. that way it doesn't matter in which order you have your turbines or whether you have 2 normal turbines vs 1 good one and 1 awful one, but having 2 turbines with a power_per_turbine of 30 is slightly better than 3 turbines of 20.
>>2988 >you can check for yourself that with 0 turbines you get power=0 Nope, when self.power_per_turbine is 0 and/or self.turbine_count is 0 I get "ZeroDivisionError: division by zero". >with 1 turbine it's power=power_per_turbine Yes as excepted >and with infinite turbines it's power=max_power How are infinite turbines represented programmatically wise? I'm not sure if Python is capable of calling "Inf" amount of objects. Current script: https://0bin.net/paste/iTHqnMlJE3rUoZ5S#HgHcQ9Uknt7FmBGlzsS2BuUgBS9m6EMyYhlHV2ROPgg With self.max_power = 100000000 Results (Without a turbine_count condition): Power: 4,850,000.0 --- Turbine: 1 Power: 9,251,311.397234144 --- Turbine: 2 Power: 13,263,445.761166818 --- Turbine: 3 Power: 16,935,835.87952859 --- Turbine: 4 Results (With a turbine_count condition): Power: 4,850,000 --- Turbine: 1 Power: 9,700,000 --- Turbine: 2 Power: 13,263,445.761166818 --- Turbine: 3 Power: 16,935,835.87952859 --- Turbine: 4 This formula at the first glance doesn't seem to be bad, but it causes power output fluctuation when I increase/decrease self.max_power despite the power output is not reaching that limit yet, is that intentional? Also when I set the self.max_power to 9700000 2 turbines will produce less power than that (= 6,466,666.666666667) > but having 2 turbines with a power_per_turbine of 30 is slightly better than 3 turbines of 20. That is a good idea, I'm trying to do something similar with the resource themselves once I have made the reactor object more complete instead of constantly jumping between changing stuff of 3 objects previously. One of the odd things I think how Factorio handles fuel value is that compared with wood and coal items that there is no difference when the total fuel stack value is calculated which results in total of 200 MJ (Wood = 100 stack size, Coal = 50 stack size).
>>2989 >Nope, when self.power_per_turbine is 0 Sure, but you've got a really shitty turbine if its designed power rating is 0. :^) Indeed, in practice you need to first check if the power per turbine is valid or by proxy whether there's any turbines, otherwise the formula doesn't make sense. >it causes power output fluctuation when I increase/decrease self.max_power despite the power output is not reaching that limit yet, is that intentional? Yes, because the formula is a simple smooth line. Last time I made an interactive graph to shed some light on the formula, but geogebra requires registration to share it so I left it at that. So here's the setup in desmos: https://www.desmos.com/calculator/v4l49zrkst If you make the power per turbine very small, like p=100 000, you'll see that the effective power grows nearly linearly with more reactors and barely changes when you slide the max power around. But the larger the power per turbine is, the more you'll see the total output fluctuate with a change in the max power, even with only 2 turbines. And the more you'll see that extra turbines have diminishing returns.

Report/Delete/Moderation Forms
Delete
Report

Captcha (required for reports and bans by board staff)

no cookies?