Skip to content

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

Merged
merged 20 commits into from
Oct 27, 2018

Conversation

depate
Copy link
Contributor

@depate depate commented Oct 2, 2018

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

@june128 june128 added Hacktoberfest The label for all Hacktoberfest related things! Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.) labels Oct 2, 2018
@Yordrar
Copy link
Contributor

Yordrar commented Oct 4, 2018

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

@Gathros
Copy link
Contributor

Gathros commented Oct 4, 2018

We have JavaScript code in the AAA.

@Butt4cak3
Copy link
Contributor

@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.

@depate
Copy link
Contributor Author

depate commented Oct 5, 2018

@Butt4cak3 Thanks for reviewing!

@@ -0,0 +1,32 @@
function forward_euler(time_step, n) {
Copy link
Contributor

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

Copy link
Contributor Author

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 = [];
Copy link
Contributor

@zsparal zsparal Oct 5, 2018

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

Copy link
Contributor Author

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.

Copy link
Contributor

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;
Copy link
Contributor

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]

Copy link
Contributor Author

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++) {
Copy link
Contributor

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);
Copy link
Contributor

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++) {
Copy link
Contributor

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 = ...
});

Copy link
Contributor Author

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;
Copy link
Contributor

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);
Copy link
Contributor

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

@Butt4cak3
Copy link
Contributor

In addition to everything that @gustorn said, we use 2-space-indentation here.

@Yordrar
Copy link
Contributor

Yordrar commented Oct 5, 2018

@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

@Butt4cak3
Copy link
Contributor

Butt4cak3 commented Oct 5, 2018

@Yordrar We do track its progress there, though. Whatever. Let's just focus on the PR. It happens. Don't worry about it.

@depate
Copy link
Contributor Author

depate commented Oct 6, 2018

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.

@depate
Copy link
Contributor Author

depate commented Oct 9, 2018

I implemented the recommendations. But I also left some questions to the change requests. :)

@Butt4cak3 Butt4cak3 self-assigned this Oct 10, 2018
Copy link
Contributor

@Butt4cak3 Butt4cak3 left a 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);
Copy link
Contributor

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?

  1. On the top level of a function, var and let do exactly the same.
  2. In a block inside of a function, var does something kind of weird while let actually does what you would expect. So let 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) {
Copy link
Contributor

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) {
Copy link
Contributor

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.

Copy link
Contributor Author

@depate depate Oct 11, 2018

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.

@depate
Copy link
Contributor Author

depate commented Oct 11, 2018

Thanks for the very detailed explanations, @Butt4cak3!

I'll get my head around it soon!

Copy link
Contributor

@Butt4cak3 Butt4cak3 left a 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;
Copy link
Contributor

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@Butt4cak3 Butt4cak3 mentioned this pull request Oct 21, 2018
@Butt4cak3
Copy link
Contributor

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.

@Butt4cak3 Butt4cak3 merged commit 03912e7 into algorithm-archivists:master Oct 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Hacktoberfest The label for all Hacktoberfest related things! Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants