-
-
Notifications
You must be signed in to change notification settings - Fork 359
Forward Euler in JavaScript #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Forward Euler in JavaScript #418
Conversation
Thanks for the contribution! We are not supporting this language yet, but when we do, we will review it. Make sure to read carefully the contributing tutorial as it says there what i just said |
We have JavaScript code in the AAA. |
@Yordrar We have lots of JavaScript already. It was one of the first languages that were contributed. I don't know where you have that information from. @depate Thank you for contributing! I took a really quick look at your code on my phone and I can already tell you that I will have a few suggestions for you as soon as I have time tomorrow. |
@Butt4cak3 Thanks for reviewing! |
@@ -0,0 +1,32 @@ | |||
function forward_euler(time_step, n) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a general note, JS uses camelCase
for everything, so the underscores kind of stand out. I would recommend sticking with the de-facto standard formatting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the information.
I confess, I did write this first attempt on JavaScript Syntax quite quickly and did not read through a style guide. I could have noticed that there. I'll catch up on the style guides, promise!
@@ -0,0 +1,32 @@ | |||
function forward_euler(time_step, n) { | |||
var arr = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In more modern JS people tend to avoid var
since it behaves in unexpected ways. For variables whose value does not change you should go with const
, otherwise let
. In this case const
would be the correct option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I got behind the usage of var, let and const. After reading about their scopes in the Mozilla Web Dev documents.
If I got it right with const
I assign a fixed identifier and a value to the variable. The identifier can't be changed, but the value it holds can.
let
is a little less strict about initial values and properties. So I could assign let a = $string
and afterwards let a = $number
. Which const would prohibit.
Both are only valid for the local control or programming structure, including further inner functions. Thus not globally available to other functions or blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@depate Yes, that's pretty much right. Your terminology might not be 100% correct, but I see that you understand the concept.
@@ -0,0 +1,32 @@ | |||
function forward_euler(time_step, n) { | |||
var arr = []; | |||
arr[0] = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just inline this with the array initialization: const arr = [1]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, if I got this right, this initialises, the arr
array with one element (the zero-eth) in the list which value is 1
. As we iterate through all n
time steps, the array gets extended by another element which value is the calculated one.
I am more used to fixed array dimensions which are allocated or set at the time of the initialisation. So I get confused all the time. But Python also is more 'flexibel' with memory allocation so I could've known better in the first place.
function forward_euler(time_step, n) { | ||
var arr = []; | ||
arr[0] = 1; | ||
for (var i = 1; i <= n; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing about var
as above. let
would be the replacement here
var solution = Math.exp(-3 * time_step * i); | ||
|
||
if (Math.abs(arr[i] - solution) > threshold) { | ||
alert(arr[i], solution); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a console.log
would be nicer here. It works in Node
as well and it's way less abrasive, even in the browser.
|
||
function check_euler(arr, time_step, threshold) { | ||
var is_approx = true; | ||
for (var i = 1; i <= arr.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The range is wrong, it should go from 0
to < arr.length
. Alternatively you could use:
arr.forEach((value, i) => {
// const solution = ...
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, here I get the general concept. One can iterate through the array directly because the array structure supports it as a method internally, great.
I am not sure about the =>
part. What is its purpose? I did not see it in the docs.
As the callback function returns the actual value of the array element, I could "simplify" the following threshold check by passing value
instead of arr[i]
, am I right?
} | ||
|
||
function main() { | ||
time_step = 0.01; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should all be declared with const
:
const timeStep = 0.01;
const threshold = ...;
n = 100; | ||
var euler_result = forward_euler(time_step, n); | ||
var check_result = check_euler(euler_result, time_step, threshold); | ||
alert(check_result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly to the previous comment, console.log
would be more user-friendly here
In addition to everything that @gustorn said, we use 2-space-indentation here. |
@Butt4cak3 Oh, yeah i searched in the archive and there is javascript... i supposed there wasn't support for it because we don't track its progress here https://github.com/julianschacher/algorithm-archive/projects srry for my blindness |
@Yordrar We do track its progress there, though. Whatever. Let's just focus on the PR. It happens. Don't worry about it. |
Thanks for reviewing as well, @Gustorn . I'll have a few questions, when I get to overhaul the code. But it won't be before today's evening. |
I implemented the recommendations. But I also left some questions to the change requests. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. @Gustorn unfortunately doesn't have the time needed to keep reviewing this, so I'll go ahead do it instead.
You did a pretty good job applying most of the suggestions, but there are still a few things left. I tried to be somewhat detailed to help you out.
const time_step = 0.01; | ||
const threshold = 0.01; | ||
const n = 100; | ||
var euler_result = forwardEuler(time_step, n); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You changed var
to let
and const
in most places, but not here. Let me get this straight: There is no good reason to use var
. Why?
- On the top level of a function,
var
andlet
do exactly the same. - In a block inside of a function,
var
does something kind of weird whilelet
actually does what you would expect. Solet
is actually better to use.
function foo() {
// <- This is where JavaScript moves the var declaration
if (true) {
var bar; // JavaScript moves this declaration to the top of the function and outside of the block
let baz;
}
}
So in case 1 let
and var
are the same and in case 2 let
is objectively better. So why use var
in the first place? I hope you can see how there's no need for it in modern code now. =)
@@ -0,0 +1,31 @@ | |||
function forwardEuler(time_step, n) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was already said about snake_case vs. camelCase also applies to variables. This should be timeStep
. The same goes for is_approx
, euler_result
and check_result
further down.
|
||
function checkEuler(arr, time_step, threshold) { | ||
const is_approx = true; | ||
arr.forEach(function callback(value, i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go from the point where this thread ended.
I am not sure about the => part. What is its purpose? I did not see it in the docs.
The arrow (=>
) is part of the arrow function syntax. It's an alternative way to create an anonymous function. But it's not just another syntax, it actually behaves differently than function () {}
. If you want to read up on the differences, you now know what to search for (arrow function). I will not go into detail here. All I will say is that you should probably get in the habit of using them. They're really quite common these days.
This is how an arrow function with a full function body would look:
const func1 = (param1, param2) => {
// Function body goes here
};
If a function only has one line in it, which is a return statement, you can omit the { }
around the function body, so these 2 are the same:
const func1 = (param1, param2) => {
return param1 + param2;
};
const func2 = (param1, param2) => param1 + param2;
I know what you're thinking. This looks kind of weird and unreadable. But trust me, it's just a syntax that you're not used to and once you're used to seeing it, it will look completely normal and you'll be able to quickly understand its meaning.
If an arrow function has only one parameter, you can also omit the ( )
around the parameter list. So these 2 would be the same:
const double1 = (num) => num * 2;
const double2 = num => num * 2;
To give you a practical example of why you would use these forms of arrow functions, here is a snippet of code that takes an array with numbers and creates a second array where all the numbers are doubled:
const doubleArr = arr.map(num => num * 2);
And finally, this is how you could use an arrow function in your code:
arr.forEach((_value, i) => {
// Function body goes here
});
Also note how I called the first parameter _value
with an underscore. That is because it's unused and by convention, you denote an unused parameter by giving it a _
prefix or simply naming it _
. Some editors like VSCode will mark an unused parameter as unused unless you prefix it with an underscore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok,
I think I got it at least for the first part. This short syntax for functions is easy, because you declare a variables value to the result of a function one evokes with a set of parameters like:
const doubleArr = arr.map(num => num * 2);
But using the same syntax just to define a function on to parameters without a result being assigned to a variable outside of it.
Intuitively I would write it somehow that inside the checkEuler function the const isApprox
gets the value of the check directly.
Something like:
const isApprox = arr.forEach(( _value, i) => {
[...] // here is the calculation of the solution variable A which gets compared later on with threshold B
if ( A > B) {
[...]
return (A > B) // returning the logical value of the check here, but I can't tell if this valid
}
});
If this would somehow be possible, then we are saving at least one line of code there. Because const isApprox
does not need to be initialised before as true
.
Edit:
I see a problem with this procedure: If A > B
is never true, which is the intended behavior, then const isApprox
will never get a boolean value. So an else
statement must be defined which produces more lines of code than the previous implementation.
I felt smart for a little moment in time.
Thanks for the very detailed explanations, @Butt4cak3! I'll get my head around it soon! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good apart from 2 more little things. Well... One of them isn't that little. It can actually crash your program. But it's a little fix.
} | ||
|
||
function checkEuler(arr, timeStep, threshold) { | ||
const isApprox = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You made this a const
, but you try to assign a new value further down. This function will either return true
or crash. This is one of those cases where let
is required.
var check_result = checkEuler(euler_result, time_step, threshold); | ||
console.log(check_result); | ||
let eulerResult = forwardEuler(timeStep, n); | ||
let checkResult = checkEuler(eulerResult, timeStep, threshold); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eulerResult
and checkResult
can also be const
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. GH did not notice me about the new review. I'm on it tomorrow.
Hey, it's been a few days since you said you'd make the changes. Just wanted to remind you that this is still open. |
Hey all!
Forward Euler in JS.
First time I did something in JS, so I really appreciate any constructive criticism about the code.
Regards
depate