A Croatian fisherman caught a new NASA device while fishing - <AUTHOR> http://alugy.com/europe/a-croatian-fisherman-caught-a-misterious-nasas-device-while-fishing/ <comment><USER2> It is a HiPAP device, used for submarine positioning:

[https://www.kongsberg.com/globalassets/maritime/km- products/...](https://www.kongsberg.com/globalassets/maritime/km- products/product- documents/hipap_family_brochure_v3_lowres.pdf?fbclid=IwAR0zm2qH4wkKrqREErRzsfevpZoEsjGz2rcEWTtt4ZdruVrFVjXZhty7PbE)

<comment><USER3> High accuracy positioning for deep-sea structure placement.

[https://www.youtube.com/watch?v=MvxeWCoAZPw&feature=youtu.be](https://www.youtube.com/watch?v=MvxeWCoAZPw&feature=youtu.be)

<comment><USER4> This plus the search pattern ("mowing the lawn") the ship is running in that area tells me that they're surveying the region accurately with sonar. There must be something on the bottom they want to find or build.

That's fairly near the location of Adria-1 submarine cable, so it's possible they are looking at something related to that.

<comment><USER3> At 1:22 of the video it shows a similar pattern being used. I'm assuming that pattern provides an inch by inch accuracy reading.

However, they could have just been testing it out in shallower waters near the coast before venturing into 1+ mile depths. Especially considering the mystery piece just recently arrived (according to the DHL tracking).

<comment><USER5> Are you all sure that is not the pattern of the ship looking _for_ the device?

<comment><USER3> _mhandley_ mentioned in a comment that the pattern tracking map is from today. It sounds like the device was returned prior to today, considering this article was published today.

<comment><USER4> The device was returned, but that pattern is the ship that likely carried/deployed the device, not the device itself.

Per another post that box is part of a fine grained positioning system, so I'd expect the ship deployed it then started doing whatever it was doing, and the fisherman trawled it up in the meantime.

</comment></comment></comment></comment></comment></comment></comment><comment><USER6> Stennis Space Center is also the location of a Naval Research Lab, and specifically the Naval Oceanographic Office and Naval Meteorology and Oceanography Command.

[https://www.usno.navy.mil/NAVO](https://www.usno.navy.mil/NAVO) [https://www.public.navy.mil/fltfor/cnmoc/Pages/home.aspx](https://www.public.navy.mil/fltfor/cnmoc/Pages/home.aspx)

"CNMOC is focused on providing critical environmental knowledge to the warfighting disciplines of Anti-Submarine Warfare; Naval Special Warfare; Mine Warfare; Intelligence, Surveillance and Reconnaissance; and Fleet Operations (Strike and Expeditionary), as well as to the support areas of Maritime Operations, Aviation Operations, Navigation, Precise Time, and Astrometry."

This is almost certainly some kind of sensor array.

<comment><USER7> What kind of sensor would be useful for finding submarine internet cables?

<comment><USER8> A phone would probably be the most useful sensor. You call the people that laid the internet cables and ask.

<comment><USER9> Russia here, can you tell me exactly where that cable is so I can do a mid ocean fiber tap, ya, thanks.

There are many clandestine reasons for finding deep sea cables.

<comment><USER10> Indeed. Croatian coastline. Possible game of phones?

</comment></comment></comment></comment></comment><comment><USER11> Note that it's almost certainly not a "NASA device;" the Navy's oceanographic office is located at the Stennis center, so it would make sense for it to be returned there.

</comment><comment><USER12> That ship route sure looks like it was looking for the lost item, whatever it is.

<comment><USER13> Either that or they were using it. Possibly towing it behind. Maybe it's some sort of sonar scanner.

<comment><USER11> Oceanographic sensor array of some kind — they may have been sampling ocean characteristics near the coastline for research purposes.

</comment></comment></comment><comment><USER14> Navy Oceanographic research is an euphemism for submarine hunting, right?

<comment><USER15> NAVOCEANO does all sorts of stuff. some of it's even unclassified.

I've taken fleet money and gotten peer reviewed open access open source publications and code out of it before.

</comment></comment><comment><USER16> Funny that the guy only asked for 3 grand. Could have probably asked for 30 and gotten away with it.

<comment><USER17> From what the fisherman says, he's really only asking for the repair costs of his fishing nets.

</comment></comment><comment><USER18> 150 pounds is quite heavy. It could be a seismic air gun. They may float just below the surface.

The route of the ship also matches that of a seismic or some other kind of survey.

</comment><comment><USER19> What's the shipping waybill from?

<comment><USER20> Huh, it's a waybill stickered to the device; in the picture with the man, you can see the shipping sticker on the front left of the orange cube.

Which makes the device boring. If it had secrets inside or it was for military use, they would not have sent it naked, using DH-effing-L!

At first I thought they sent something to the fisherman, and since he was complaining about his fishing net, I thought the article was about to tell me that he got a replacement fishing net straight from "NASA", as we can see from the DHL package he got... but sadly that wasn't the case.

<comment><USER21> Much easier to hide things in plain sight than say a big box that says "Classified" or "Government Only"

<comment><USER22> Classic story: All for $79.25: How Russia Somehow Shipped a U.S. Missile To Moscow by Mail

[https://warisboring.com/the-kgb-shipped-a-sidewinder- missile...](https://warisboring.com/the-kgb-shipped-a-sidewinder-missile-by- mail-to-moscow/)

</comment></comment></comment></comment><comment><USER23> This fisherman might be a tough negotiator, but clearly not a keen businessman. Could've gotten a top coin from the Russians for the same. I'm sure they even have a sub in the area already.

<comment><USER24> The Russians could just buy one if they were so inclined; I don't think HIPAP devices like the one pictured are under export control. (The HIPAP is just the yellow pipe - the orange thingy looks like flotation whereas the glide pads on the sides are to make launching the device simpler.

(I haven't worked on such kit myself, but my customers do and I encounter them several times a year.)</comment></comment>


Ask HN: Feedback on a Startup Idea: BPA Testing - <AUTHOR>

I always hear how terrible BPA is but I can't seem to find out which products and foods have it and which don't.
So the startup woud just be a company that tests popular consumer items (food, products that come into contact with food) for BPA and publishes (sells?) the results.
What do you guys think?  Why has no one done this? <comment><AUTHOR> Hmm, usually ask HN has been much more helpful. Was my question too vague? Not internety enough?

<comment><USER2> I don't think it's in the normal areas of HN reader's competence, plus only people like me who look at every item are sure to see it.

What you propose would be pretty expensive to do, wouldn't be all that reliable as companies change their packaging etc., and how would you get (enough) people to pay for it.

I'm also pretty unimpressed with what I gather about the furor over it. I haven't studies _this_ scare, but it smells a whole lot like others that I have studied since the '70s and that were totally bogus. E.g. saccharin, and someone I trust told me the cyclamate ban was based on feeding calcium cyclamates to calcium sensitive rats ... which is particularly bogus when sodium cyclamate is the type used; see <http://en.wikipedia.org/wiki/Sodium_cyclamate> where even Wikipedia admits there's no problem with them.

One of these days the environmentalists will probably find something truly dangerous ... but after crying wolf so many times, well, it will be too bad.

(For the record, while an appeal to authority shouldn't carry much weight, I was a Chemistry major at MIT, although finances prevented me from finishing.)

<comment><AUTHOR> Thanks for the feedback. You have some good points. It still seems strange to me that no one has stepped in to report on what products have BPA.</comment></comment></comment>


How (and why) Reactive microservices are mainstreaming w enterprise developers - <AUTHOR> https://developer.ibm.com/dwblog/2017/reactive-microservices/ <comment><USER2> It's good to see the spread of microservices as it's a better way to develop scalable applications. Nice that there's so much innovation in this space.</comment>


Ask HN: Open Source Pivotal Tracker/Basecamp alternative? - <AUTHOR>

I've had success using Pivotal Tracker, JIRA, and other project management tools in the past.  Now I want to install something like that on my own server.  I'd like to do it on my shared hosting account, so a PHP solution is preferred, but I would also look into things I can put on my dedicated box.  I prefer Pivotal Tracker's interface over the other alternative.  And yes, I've also had previous success with Google Docs, but that's not what I'm looking for here - I'm looking for something specifically similar to Pivotal Tracker. <comment><USER2> I heard people recommending Redmine - didn't work with it myself though.</comment>


Free Adobe CS2 suite dl. Straight from adobe.com. Link in text. - <AUTHOR>

Straight from the adobe website itself complete with serial numbers for install. ms or mac dls as well.
http://www.adobe.com/downloads/cs2_downloads/index.html
Can this day get any better? <comment><USER2> Super excited until I realized that I need CS3 or newer for a recent OSX.

<comment><AUTHOR> sorry about that, but it is most definitely legit.

You can try using a windows emulator or something, I don't use a mac, but I'm certain a solution is out there!

<comment><USER2> No worries... That's what I do today. It's a good find regardless.</comment></comment></comment>


Hydroxychloroquine Tied to Deaths, Heart Risk in Covid Study - <AUTHOR> https://www.bloomberg.com/news/articles/2020-05-22/hydroxychloroquine-linked-to-deaths-heart-risks-in-covid-study <comment><USER2> Expression of concern: Hydroxychloroquine or chloroquine with or without a macrolide for treatment of COVID-19: a multinational registry analysis

[https://www.thelancet.com/lancet/article/s0140673620312903](https://www.thelancet.com/lancet/article/s0140673620312903)

</comment><comment><USER3> Absolute garbage. The study confirms that sicker patients get hydroxychloroquine more frequently than less-sick patients. When sicker patients get drugs, "Treatment with any combination of the four drugs was associated with a higher risk of death than seen in 81,000 patients who didn't receive them."

And...why don't the study authors control for zinc use as well? "Hydroxychloroquine is a zinc ionophore", explains one paper.

<comment><USER4> > The study confirms that sicker patients get hydroxychloroquine more > frequently than less-sick patients.

Wait, where does it say that in the study? The study specifically says it controls for disease severity (amongst other things), and that it only uses data for people given the drugs within 48 hours of diagnosis.

<comment><USER3> "Within 48 hours of diagnosis" indicates nothing about disease severity, nor how long patients were sick prior to diagnosis.

> Wait, where does it say that in the study? The study _supports_ the idea > that sicker patients get hydroxychloroquine more frequently than less-sick > patients. The study's raw figures show that sicker patients get > hydroxychloroquine more than healthier patients.

The study states that besides age and BMI, "all other [control] data were treated as categorical variables in the model."

It's clear the study's authors don't sensitively control for patients' angiotensin-renin-aldosterone system health.

There's strong subject selection bias in "initial disease severity" as well when some subjects die at home and others go to the ER mistaking mild Covid for heart attack symptoms.

</comment></comment></comment><comment><USER2> Retracted: [https://www.thelancet.com/lancet/article/s0140673620313246](https://www.thelancet.com/lancet/article/s0140673620313246)

[https://twitter.com/TheLancet/status/1268613313702891523](https://twitter.com/TheLancet/status/1268613313702891523)

</comment><comment><USER2> More technical discusson: [https://news.ycombinator.com/item?id=23273615](https://news.ycombinator.com/item?id=23273615)

</comment><comment><USER5> There were multiple posters here on HN advocating for Hydroxychloroquine saying that it's safe, that you have nothing to lose otherwise and that it's better to try something than do nothing.

So unfortunately what we have here is a textbook example of people falling for a cargo cult surrounding a drug whose efficacy wasn't confirmed at all. Even if a drug seems safe and has few side effects, you should never self-dose or listen to people without medical consensus.

<comment><USER6> Call me crazy, but there is something interesting I observed. Before Trump started advocating for it, there were some articles touting Hydroxychloroquine as a potential Covid-19 treatment, and that it was worth trying. Immediately after Trump started advocating for it, Hydroxychloroquine became like a poison, that will kill everyone. Isn't that great? I wish more things would receive this level of scrutiny before being inflicted on vulnerable and desperate people.

<comment><USER7> This is an artifact of the way the news was presented where you read it: this is an old drug with well-understood side-effects and actual experts (pharmacists, doctors, patients) pointed those out almost immediately.

The problem is that the people hyping it through either desperation or greed have a lot more time to spend promoting an idea than, say, medical professionals during a pandemic — a dynamic which got much worse when the full weight of Fox News and the President of the United States jumped on board the hype train.

</comment></comment></comment><comment><USER8> Confirming what we've known all along

</comment><comment><USER2> [https://spectator.org/lancetgate-pulling-a-fast-one-on- propo...](https://spectator.org/lancetgate-pulling-a-fast-one-on-proponents- of-hydroxychloroquine-and-chloroquine/)

[https://news.yahoo.com/lancet-casts-doubt-over- hydroxychloro...](https://news.yahoo.com/lancet-casts-doubt-over- hydroxychloroquine-study-130453194.html)

</comment><comment><USER9> It's probably too early to draw conclusions. Many doctors seem to think it is the best treatment available: [http://nypost.com/2020/04/02/hydroxychloroquine-most- effecti...](http://nypost.com/2020/04/02/hydroxychloroquine-most-effective- coronavirus-treatment-poll/)

I think people should resist politicizing this because they are for our against Trump. It is normal for both medicine and the scientific process in general to have a multitude of voices with diverse opinions.

<comment><USER10> It's practically obscene that anyone thinks that Trump's mention should in any way affect their thinking about a drug. People are dying--let science run its course unhindered.

</comment></comment><comment><USER11> I am hoping come the November elections that Trump will be gone. He has made the US look incredibly stupid in the rest of the world's eyes.</comment>


Show HN: Vim³ – Vim rendered on a cube for no reason - <AUTHOR> https://github.com/oakes/vim_cubed <comment><USER2> My kind of silly project. I'd add this to the faq:

But? No.

</comment><comment><USER3>
      ¿ʎɥʍ

<comment><USER4> You very well know why.</comment></comment>


Twitter, PayPal reveal database performance - <AUTHOR> http://www.itnews.com.au/News/317811,twitter-paypal-reveal-database-performance.aspx

<comment><USER3> I always knew the company I work for does cool things with MySQL, but I never knew how far we really have pushed the envelope until I see how much more we push MySQL then the twitters and facebooks of the world. Doing some napkin math I would say our largest cluster of MySQL does about 320 Billion inserts a Day across 80 nodes and some of our nodes can peak at about 200K queries per second ( that would be 16 Million QPS if all the nodes were fully loaded ). Meaning at one of our installs we do the same volume as two facebooks !

<comment><USER4> Out of curiosity, what industry do you work in?

<comment><USER3> Performance Monitoring.

<comment><USER5> Coincidently I work on performance monitoring at Facebook. We gave up logging perf data to MySQL because it was a management headache at scale. So instead my colleagues built Scuba, which is essentially a search engine they taught to perform aggregate functions.

[http://gigaom.com/cloud/exclusive-facebooks-scuba-project- di...](http://gigaom.com/cloud/exclusive-facebooks-scuba-project-dives-into- performance-data/)

<comment><USER3> Lots of people gave up trying to do their own performance logging, it turns out its a non trivial problem when you get to large scale systems. Which is why the company I work for exists.

<comment><USER5> Does the name start with New and end with Relic, by chance? :) I'd love to compare notes sometime. My email's in my profile.

<comment><USER3> No, but I understand why you might think that. I sent you an E-mail.

<comment><USER6> Your company is easy to find on Google. It's not stealth, and it's venture- funded. Curious why you can't or won't mention the name here.

<comment><USER3> I am in no way an official spokesperson for them, just a developer, I don't know how much publicity I am allowed to draw to our back end architecture without getting into trouble. It is after all the thing that separates us from everyone else out there. (BTW I have posted the Who's Hiring post a couple times so my Username is pretty easy to track to whom I work for)

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER4> Not surprising, especially if you've ever used their interface or API. I'm reasonably certain that they don't have any indexes.

Slowest API ever....

<comment><USER7> The sandbox they provide is even worse in terms of response times.

<comment><USER8> And lacks documentation. Or the documentation that is there is wrong. Or it's there but missing fundamental details. Or it's right but you question how it could possibly be a good design decision.

<comment><USER7> Or the documentation that describes something like it works in the sandbox, but not in the production system or vice versa. Developing for Paypal is a lot of fun.

</comment></comment></comment></comment><comment><USER9> The speed of their transaction search actively discourages me using it. It is extremely slow even when searching by the transaction Id which you would assume at least that would have a decent index on it.

<comment><USER10> Have you EVER actually worked on a reasonably sized system ?

Because there are a lot more contributors to request/response performance than just database indexes. Especially when you are at the scale of Paypal.

<comment><USER11> I have, and I can tell you that the speed at which they are able to search for transactions is disturbing. Regardless of if it's related to indexes or another cause, it's still a huge issue for people who have to use PayPal. That appears to be the point the parent comment was trying to make.

Your comment had the potential to be constructive and educational, but instead you took a condescending approach. That's unfortunate.

</comment></comment></comment><comment><USER12> _"get a timestamp error if one node attempts to read data that was written by another node in the future (due to data moving across datelines)"_

Honest question: Which part of a replication/db system would be using time stamps that weren't universal?

<comment><USER13> Just the concept of using time for the logical clock is sketchy. It's not monotonically increasing, it drifts, it can go decrease, etc... Curious what their cross host/region ordering and consistency looks like.

<comment><USER14> "An atomic clock is not that expensive." -- <http://research.google.com/archive/spanner.html>

<comment><USER15> Indeed. A GPS clock accurate to 50ns is around $25 on eBay.

</comment></comment></comment></comment><comment><USER16> curiously, 4629 tweets a second is 4 million a day[1], which is more than the number of rows per day (3 million).

this must be someone not thinking, right? i don't see how they can have less rows than tweets. even with de-duplication of repeated text they still need a key (and timestamp) per tweet.

oh! and it gets worse. the next line says "400 million new tweets a day". that one must be plain wrong (it's a rate 100x higher than the number per second), given that the other two are (comparatively) consistent (it would also mean an average of 3 tweets per day per active user (140 million), and i suspect they define active user to be anyone over 1 tweet per month...).

 _so the section "by the numbers" contains four items, but only two independent values. and appears to be inconsistent twice._

[1] almost exactly - presumably the per second value is derived from a rough figure for the daily value.

<comment><USER10> Yes because finding ways to not insert a new row for each tweet is a classic sign of someone not thinking.

From the UI Twitter only shows tweets to the minute so you could imagine that there is an optimisation there for merging retweets with the same text within a 60 second period.

<comment><USER17> Assume they normalized the timestamp, and only stored something on the level of "these people tweeted/retweeted this message sometime during this 60 second interval."

The only way to avoid adding a new row per account that tweeted/retweeted would be to store the list of account in a single row, and keep updating it on every re-tweet. This seems like it would be a less than optimal solution.

<comment><USER16> it certainly seems like you would need to aggregate keys somewhere (if it's not the typo i assumed). that might just be possible in postgres these days (update: a quick google suggests it's in development for 9.3), but i am pretty sure not in mysql. on the other hand, for all i know, at this scale, they may be treating mysql as some kind of distributed hashtable and doing a lot more work in higher layers...

[ _update: I completely screwed up the maths; looks like this is not rows per tweet, but support data._ ]

<comment><USER17>
      > for all i know, at this scale, they may be treating
      > mysql as some kind of distributed hashtable and doing
      > a lot more work in higher layers...

If MySQL is just used as hash table, and all of the interesting stuff happens at higher layers, then talking about the number of rows isn't that meaningful.

</comment></comment></comment></comment></comment><comment><USER18> Twitter, Paypal don't really need to be that fast. Nor does Facebook.

But do you think major banks on Wall Street tracking billions of trades a day in near real-time would be satifisfied with these numbers?

It all depends on what your users demand and what they will put up with.

</comment><comment><USER19> If anyone is interested in watching Jeremy's presentation online it can be found at:

<http://medianetwork.oracle.com/video/player/1873920417001>

</comment><comment><USER20> What I would really like to see is a guesstimate of the volume of user behavior/analytics data that FB/Twitter generate. It would be interesting to see the average amount of data per user-interaction.

</comment><comment><USER21> That's surprising to me. I didn't expect financial transactions to create that much data. Also wouldn't most of the data be archived and only rarely be accessed?

<comment><USER22> Financial transactions tend to create a lot of data for the logging and recoverability they require, and the logging isn't terribly interesting.

The trick is realizing that things can and do fail in any way for any reason _, and being able to automatically recover from any point in that process. Our (WePay's) system currently requires, at an absolute minimum, seven inserts across six tables, though more commonly 9-10 rows across seven, plus updates on several others, and significantly more if we can't authorize the payment on the first attempt (e.g., mistyped ZIP code on your billing address). Only one of those tables is for logging (account_history, which is functionally identical to a check ledger).

I've completely ignored both the logging of state changes (largely redundant at this point, it was more for early debugging a couple years ago, but still sometimes useful for figuring out why something stalled) and recording of fraud-detection data which can easily be a hundred rows, albeit very small ones (80 bytes or so). It's also interesting to look at what updates need to be performed in a transaction and which ones don't, although that's of course irrelevant to the actual amount of data produced.

That doesn't account for the product side of payments at all - <USER2> contents of shopping carts, donations, ticket purchases, etc. That's at best one stateless row, but use your imagination about the data layout for various money-collecting tools.

Archival is interesting and something I'm sure we'll look at more in the future, but right now it would tend to create more problems than it solves -- we have automated data integrity checks running multiple times per day to ensure nothing is out of line, and kicking data out to an archive somewhere would complicate that significantly. We also of course don't have nearly as much data as PayPal being significantly newer, so it's less of a problem.

_ conflicts/row locks being one of the more common, but that's easy to deal with. It's when an external call to a processor dies halfway through that things get tricky.

</comment></comment><comment><USER23> It'd be great to read about people's experiences using postgres on a comparable scale to that discussed in this article ... does that even happen?

<comment><USER24> Yahoo had a huge postgres database a few years ago. No idea what they are doing now. [http://www.computerworld.com/s/article/9087918/Size_matters_...](http://www.computerworld.com/s/article/9087918/Size_matters_Yahoo_claims_2_petabyte_database_is_world_s_biggest_busiest)

And Skype sounds pretty interesting too. [http://www.slideshare.net/adorepump/small-overview-of- skype-...](http://www.slideshare.net/adorepump/small-overview-of-skype- database-tools)

</comment></comment><comment><USER25> Does the "commercial instance of MySQL" refer to Percona, something else, or is it simply the MySQL commercial license?

<comment><USER26> The article author is confused. I clearly stated in the presentation that we're developing our own branch of MySQL, which is available on Github:

<https://github.com/twitter/mysql></comment></comment>


The Way of Chinese Language - <AUTHOR> http://thevivekpandey.github.io/posts/2019-02-02-way-of-chinese-language.html <comment><USER2> This was interesting but a lot of the things are wrong. Mandarin _does_ have words. They are just composed of characters instead of letters. And there is NO way you could read a Chinese newspaper by just knowing what the characters "mean". Some characters don't mean anything, and they're just there for grammatical reasons. Other characters can get mixed with completely unrelated characters and get a totally unrelated meaning to either. So for those of you who don't know Mandarin, please read a lot of this with a grain of salt.

Regarding the simple grammar, I'll say that tenses and plurals are easy for an English speaker to pick up. But Mandarin introduces new grammatical requirements that English and most other languages don't even have constructs for, like change of state (which serves as the past tense in many situations) or counting words. Once you move beyond the "simple" grammar, things get complex fast.

<comment><USER3> Yes, there are words in Chinese. A lot of them make sense while others do not.

Chinese use compound words a lot. For example, there is "午餐", which means "Lunch", where "午" means "noon" and "餐" means "meal". In this way, it is more like German "Mittagessen" where "Mittag" is "noon" and "Essen" is "eating".

There are also a lot of words do not make sense like "天真", which means "naive", while "天" means "sky" and "真" means "real(ly)". This does not make sense at all.

Still, most of the words are just between these two categories. For example "自然" means "nature", and "自" means "itself" and "然" means "happened". So "nature" means "it just happened itself". This is kind of make sense somehow but it is actually pretty blurred for most people.

<comment><USER4> 天真 = innocent, why 'sky' or better 'heaven'? 'Heavenly real'. It makes sense, but translation doesn't work. Concept is hard to be translated into another language.

<comment><USER5> It's not just a translation issue, but that the composition is just archaic. The constituents had real meaning a long time ago when they became a word, but today you just understand 天真 as its own word and move on. If you didn't know that word but understood 天 and 真 you wouldn't be able to figure out the word's meaning.

The same is true with many English words as well actually: many of them started out as composites that were meaningful in the last but today are not. For example, "understand."

</comment></comment></comment></comment><comment><USER6> > In some cases, characters are composed of two parts: a radical element and a > pronunciation hint

Actually something like 80% of characters are phonetic-semantic. More info: [https://www.hackingchinese.com/phonetic-components- part-1-th...](https://www.hackingchinese.com/phonetic-components-part-1-the- key-to-80-of-all-chinese-characters/)

</comment><comment><USER7> Of note is that the current mainland govt wasn't the one to start the simplification of Chinese characters, it start with the original Republic of China but was abandoned by Taiwan because it was associated with the Leftist side of the Republic of China as left-leaning and liberal Chinese scholars saw traditional Chinese as inhibiting Chinese education for the masses and promoted simplification.

Singapore and Malaysian Chinese also uses Simplified Chinese.

</comment><comment><USER8> As someone who learned English from Spanish, this strikes me as totally off:

> In English, if you can speak something, you can write it too

Compared to Spanish, Italian or Japanese hiragana/katakana, this is not true at all in English. It is _more true_ than in Chinese/Japanese (Kanji), but still not much. It is in fact one of the things that English Learners struggle with the most!

</comment><comment><USER9> Hey this was pretty interesting - the most in-depth introduction to Chinese characters I've seen.

</comment><comment><USER10> One recommendation: When learning Characters, write them out physically (or in an app)

The characters are designed to be written with a brush dipped in ink. The shape, order and direction are arranged such that a right handed person has minimal chances of smudging prior strokes.

This kind of muscle memory seems to be very beneficial even to recognizing the characters (much like autoencoders or transfer learning in AI).

<comment><USER11> In my experience, unless you want to be able to write characters without machine assistance, it's faster to just learn to recognize them without spending time on writing them out. Being able to recognize the rough stroke order is a little helpful, but not necessary unless you want to look up characters by stroke count. But since tools for character lookup are fairly sophisticated today, you don't really need paper dictionaries anymore. The only benefit I can see is in the ability to read handwritten characters. The "cursive" script is basically impossible to read unless you know the stroke order really well.

<comment><USER10> Are you able to read 2000 characters fluently?

I'd be interested because so far I mostly hear from people trying this approach, but not actually succeeding.

I would agree that the value of writing characters diminishes quickly after the first few hundred.

<comment><USER12> I can read a few thousand characters (I pick up new characters by adding flashcards (using Anki) when reading novels written in Chinese). At this point I rarely encounter characters I can't read (but there are frequently words I don't know).

I can only write a handful of characters (probably less than 100?).

I probably would get the characters mixed up less frequently if I practiced writing them, but I don't think I would have been able to learn so many if I was doing that.

<comment><USER10> That sounds like you actually did practice writing the characters at the beginning. Which is my strategy also.

</comment></comment></comment></comment></comment><comment><USER13> Pretty good introduction! The one thing I found a little off was in the larger phrase constructions: the explanation of how larger "words" are formed from characters isn't quite right. For instance the example of "socialism", 社会主义, which he parses as "common production primary virtue", isn't really four words in a row, it's two "words" made of up two characters each: 社会 meaning society, 主义 typically used as an "-ism" suffix.

义 in isolation might mean "virtue", but most characters have a handful (or more) of meanings, and when it comes after 主, 义 takes on more of its "idea" meaning.

But all in all, pretty good!

</comment><comment><USER14> "Perhaps you can spot an elephant in 象"

The animals: [https://en.wikipedia.org/wiki/Oracle_bone_script#/media/File...](https://en.wikipedia.org/wiki/Oracle_bone_script#/media/File:Oracle_bone_graphs_rotated_90_degrees.svg)

<comment><USER15> Go to [http://hanziyuan.net](http://hanziyuan.net) and put in 象. It's not hard to see the elephant.

I particularly like B14607.

</comment></comment><comment><USER16> Mandarin does have words. Sometimes you can deduce a meaning of a compound word from the literal meanings of the characters it's made up of, but sometimes you cannot.

It also doesn't aid you in pronouncing it because it's not obvious which tone it is, unless you already know it.

</comment><comment><USER17> [Shameless plug] My own take on the birth, evolution and Mao's simplification of Chinese writing: [https://al3x.svbtle.com/on-chinese- writing-1](https://al3x.svbtle.com/on-chinese-writing-1)

</comment><comment><USER18> Happy Chinese New Year!

I cannot stop helping myself to share a Chinese quiz to you for celebrating our new year - please use 20 different Chinese words to express "I" or "me".

</comment><comment><USER19> In one part the author says "In English we write them identically, but we speak them differently: in different tones.". A few paragraphs later, he states that English speakers have trouble with the 4 tones of Chinese, which are so obvious to the Chinese, and that phonetic languages don't use tones. Which is it? I thing each language has tones, but they are different tones, and therefore unfamiliar and maybe difficult for speakers of the other language to grok.

(Funny but inappropriate comment self-censored.)

<comment><USER20> English does use pitch in prosody, but it's not phonemic. (There aren't pairs of English words that are distinguished only by their pitches or pitch contours.) We'll never get a full-scale English equivalent of

[https://en.wikipedia.org/wiki/Lion- Eating_Poet_in_the_Stone_...](https://en.wikipedia.org/wiki/Lion- Eating_Poet_in_the_Stone_Den)

A more precise way that the author could have made this point might be something like this: "In English, we do sometimes use pitch to convey meaning, for example to show which word in a sentence is most important, to show whether a sentence is meant as a question or not, and to show certain kinds of emotion. But it doesn't cause one word to turn into another. In Chinese, it often does."

<comment><USER21> >There aren't pairs...

That is quite a claim.

Off the top of my head:

digest, digest

regress, regress

contract, contract

implant, implant

etc.

<comment><USER22> That's to do with stress, not tone. For tone, think about the difference between English "(I know) you want to leave." vs "(Do) you want to leave?"

<comment><USER21> No, you're talking about a different thing.

Each of the listed words can also have stress applied, or not, in different ways and still be differentiated by the "tone" as it would be called in Chinese. I'm not calling it tone since we don't really have a word for it other than "pronunciation" but it's essentially the same thing as what is happening in Chinese with tones, albeit with a very limited set of cases rather than being a pervasive feature of the language.

But feel free to call the thing I'm talking about whatever you want. But calling it "stress" doesn't make it the same thing as the kind of stress that you were talking about with your example sentences.

<comment><USER21> Compare:

Did HE contract the disease?

Did he CONTRACT the disease?

In each of these sentences, if you pronounce "contract" as it were a noun describing a legal agreement, you are going to sound somewhat off. Same with the other words listed.

Well, that is, unless you and your listeners don't know how to pronounce "contract" differently in each usage. But again this is only one of the examples.

<comment><USER22> This is what I get from your examples - four possibilites:

1\. Did HE contráct the disease? - "Was it that person (or someone else) who got infected with the disease?"

2\. Did HE cóntract the disease? - "Was it that person (or someone else) who commissioned a third party (to create?) the disease?"

3\. Did he CONTRÁCT the disease? - "Is the thing that happened with him and the disease that he got infected with the disease, or something else?"

4\. Did he CÓNTRACT the disease? - "Is the thing that happened with him and the disease that he got a third party to create the disease, or something else?"

The ALLCAPS is likely focus prosody, but there's still a differenced from 'catching' and 'commissioning' which is usually referred to a difference in the placement of 'stress' within the word - whether it's on the first syllable or the second syllable (in this case). Since English is stress-timed, it also affects vowel quality. But that's rather different from tone. (Or, to abstract away from terminology the difference between English 'cóntract' (commission) and 'contráct' (catch) is different from what goes on in Mandarin with tone distinguishing between lexical items.)

<comment><USER21> Actually your four don't capture my meaning. There is one missing.

3\. Did he CONTRÁCT the disease? .. 5\. Did HE contráct the disease?

Does that make it more clear? In other words, these sentences show the same "tones" (different from "tone"), but different stress.

You were saying tones are just stress, but they are not. The stress here is different from the tones.

With #3, the stress is on "contract"; with #5, the stress is on "he"; the "tones" (again in quotes because we don't really use that word for it in English, although I'm saying the underlying phenomenon is the same) are the same in both, although the stress is different.

You can change the tones and the stresses independently of each other, and when you change the tones of the syllables, you get different meanings for the words.

<comment><USER22> I think we're using 'stress' and 'tones' to refer to completely different things. I think you're using 'stress' to mean something like what I would call 'focus prosody', and you're using 'tones' to mean what I would call 'stress'. But, in terms of the acoustics, 'focus prosody' is closer to Mandarin lexical tones (though not in function).</comment></comment></comment></comment></comment></comment></comment></comment></comment>


Recursive fibonacci benchmark using top languages on GitHub - <AUTHOR> https://github.com/drujensen/fib <comment><USER2> ok, owner of the repo here. So this project was purely to show the macro differences between interpreted ruby and compiled crystal to beginner ruby devs at a meet up.

I decided to add the top languages on github to help give some idea of how crystal performed against them.

I'm happy to see so much discussion about it and was taken by surprise when my inbox was full this morning. Thanks @anonfunction. ;-)

The breaking benchmark examples were just that, examples of how to break the benchmark. I didn't expect to get a memoized version of every language and really don't think comparing them from a performance benchmark makes much sense. Let me know if i'm wrong about that.

I am fine adding all of your change requests and will try to keep the benchmarks up to date.

<comment><USER3> I used to benchmark using fibonacci, but the recursive method is just awful because it does a lot of function calls and you're essentially benchmarking that. Then I switched to finding primes using the Sieve of Sundaram. It uses arrays, hashes/maps/dicts and two loops. Also wastes a lot of memory if you don't split your search domain into ranges. The surprise was that Go and D (in that order) turned out to be faster than Rust mainly due to Rust's HashMap SipHash algorithm. I gave up trying to use other hash libraries (SeaHash specifically) that are not part of the standard lib, because it was quite frustrating compared to D.

<comment><USER4> > gave up trying to use other hash libraries

 _fwiw_ a Rust k-nucleotide program using indexmap:

[https://benchmarksgame- team.pages.debian.net/benchmarksgame/...](https://benchmarksgame- team.pages.debian.net/benchmarksgame/program/knucleotide-rust-4.html)

</comment></comment></comment><comment><USER5> So... before looking at the code, I compared the elapsed time between the fib.rs program compiled with `rustc -O` and `rustc -O -C lto`. This yielded, interestingly, a ~500ms difference: ~6.45s vs ~6.95s (with LTO winning).

Then I looked at the code, and it began to make no sense. Then I looked at the assembly, and it made even less sense: the main function, fib::fib, which is where the vast majority of the time is spent, is identical, except for addresses.

I was starting to think, well, this might be related to instruction-cache lines... and it looks like it's not that:

      $ perf stat ./fib-lto
      2971215073

       Performance counter stats for './fib':

             6474.410894      task-clock (msec)         #    1.000 CPUs utilized
                      17      context-switches          #    0.003 K/sec
                       0      cpu-migrations            #    0.000 K/sec
                     112      page-faults               #    0.017 K/sec
          22,607,598,238      cycles                    #    3.492 GHz
          55,325,512,417      instructions              #    2.45  insn per cycle
          13,021,149,180      branches                  # 2011.171 M/sec
              76,737,179      branch-misses             #    0.59% of all branches

             6.474991613 seconds time elapsed

             6.474816000 seconds user
             0.000000000 seconds sys

      $ perf stat ./fib
      2971215073

       Performance counter stats for './fib':

             6956.534790      task-clock (msec)         #    1.000 CPUs utilized
                      11      context-switches          #    0.002 K/sec
                       0      cpu-migrations            #    0.000 K/sec
                     113      page-faults               #    0.016 K/sec
          24,290,924,647      cycles                    #    3.492 GHz
          55,325,864,841      instructions              #    2.28  insn per cycle
          13,021,213,404      branches                  # 1871.796 M/sec
              84,392,454      branch-misses             #    0.65% of all branches

             6.957260487 seconds time elapsed

             6.956974000 seconds user
             0.000000000 seconds sys

I didn't know an address difference of 0x30 could influence the number of branch misses so much.

<comment><USER5> Interestingly, the C and C++ versions have different performance for the same reason: they produce the exact same machine code, at different addresses. Thus one runs faster than the other. _Edit: actually, there isn 't a difference in branch-misses for those... only in cycles, which is even more intriguing._

Another interesting fact: valgrind's branch simulator doesn't show a difference in branch mispredictions between both (it also shows a misprediction rate much larger than reality, it's likely based on an old model _Edit: valgrind manual says: Cachegrind simulates branch predictors intended to be typical of mainstream desktop /server processors of around 2004._).

 _More edit_ : I hacked a linker script to place the fib function from the C++ implementation at a fixed address, and tried different addresses, with interesting results:

      0x10000: 5.117084095 seconds time elapsed, 17,866,364,962 cycles
      0x10010: 5.206242916 seconds time elapsed, 18,090,712,907 cycles
      0x10020: 6.096635146 seconds time elapsed, 21,285,484,583 cycles
      0x10030: 4.955020420 seconds time elapsed, 17,297,162,836 cycles
      0x10040: 5.146043048 seconds time elapsed, 17,954,722,919 cycles
      0x10050: 5.252477508 seconds time elapsed, 18,335,804,193 cycles
      0x10060: 6.100806292 seconds time elapsed, 21,300,089,284 cycles
      0x10070: 4.936397948 seconds time elapsed, 17,216,051,020 cycles

_Even more edit_ : I vaguely remember there was someone doing some analysis (with performance counters) of some similar performance difference depending where the function was located, that was on HN a few months ago, but I can't find it anymore.

<comment><USER6> An Intel engineer gave a presentation at the 2016 LLVM Developers' Meeting that gives some insight: [http://llvm.org/devmtg/2016-11/Slides/Ansari-Code- Alignment....](http://llvm.org/devmtg/2016-11/Slides/Ansari-Code- Alignment.pdf) (for the slides).

Essentially, some of the loop heuristics work on a 32-byte window, not a 16-byte window. An interesting statistic would be to find where all the loops are in the code as relative offsets, and find how these shift based on starting alignment.

<comment><USER5> Thanks. This looks familiar, but I thought I had seen something similar in a blog form. _Edit_ : Found it! [https://dendibakh.github.io/blog/2018/01/18/Code_alignment_i...](https://dendibakh.github.io/blog/2018/01/18/Code_alignment_issues) [https://news.ycombinator.com/item?id=16198171](https://news.ycombinator.com/item?id=16198171)

FWIW, this is what the function looks like at 0x10070:

      0000000000010070 <_Z3fibl>:
       10070:       48 83 ff 01             cmp    $0x1,%rdi
       10074:       7e 32                   jle    100a8 <_Z3fibl+0x38>
       10076:       55                      push   %rbp
       10077:       31 ed                   xor    %ebp,%ebp
       10079:       53                      push   %rbx
       1007a:       48 89 fb                mov    %rdi,%rbx
       1007d:       48 83 ec 08             sub    $0x8,%rsp
       10081:       48 8d 7b ff             lea    -0x1(%rbx),%rdi
       10085:       48 83 eb 02             sub    $0x2,%rbx
       10089:       e8 e2 ff ff ff          callq  10070 <_Z3fibl>
       1008e:       48 01 c5                add    %rax,%rbp
       10091:       48 83 fb 01             cmp    $0x1,%rbx
       10095:       7f ea                   jg     10081 <_Z3fibl+0x11>
       10097:       48 83 c4 08             add    $0x8,%rsp
       1009b:       48 8d 45 01             lea    0x1(%rbp),%rax
       1009f:       5b                      pop    %rbx
       100a0:       5d                      pop    %rbp
       100a1:       c3                      retq
       100a2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
       100a8:       b8 01 00 00 00          mov    $0x1,%eax
       100ad:       c3                      retq

Edit: It's interesting to note that there's only one recursive call to the function, not two (you get two calls if you compile with -O1). It's also interesting to note that -Os generates an even smaller version with only one recursion, but that ends up slower (~6.5s).

<comment><USER7> The compiler has determined that the second call `fib(n - 2)` is "almost" tail-recursive (there is probably a better term for this), and so was able to convert that call into the loop you see at 10081 to 10095. This loop repeatedly calls the `fib(n - 1)` part.

In other words, the function was transformed from:

      uint64_t fib(uint64_t n) {
        if (n <= 1) return 1;
        return fib(n - 1) + fib(n - 2);
      }

into the equivalent of:

      uint64_t fib2(uint64_t n) {
        if (n <= 1) return 1;
        uint64_t sum = 1;
        for (; n > 1; n -= 2) {
          sum += fib2(n - 1);
        }
        return sum;
      }

Unfortunately, the result isn't too great as the initial part of the function is pretty heavy, and this bottlenecks computation. It would be better to inline some copies of fib into itself which might even allow some small amount of CSE, but importantly would reduce the number of calls.

The alignment you show is "special" (fast) because it's the point at which the top of the main loop (10081) is near the start of a 32-byte region, which allows multiple uops to be efficiently dispatched after jumping there.

</comment></comment></comment></comment></comment><comment><USER8> The owner of this repo has no idea it's trending on HN. This issue gave me a good laugh: [https://github.com/drujensen/fib/issues/51](https://github.com/drujensen/fib/issues/51)

<comment><USER9> On the flip side, HN just won itself a new user.

<comment><USER2> lol, yes it did.

<comment><USER10> Your project is informative and awesome, I hope you don't mind the attention.

</comment></comment></comment></comment><comment><USER11> Sorry, but this is _not_ how you do numeric benchmarks. Most real programs that deal with numbers also manipulate data structures and call many standard library methods. If those things are slow, your app is slow. This benchmark doesn't demonstrate anything that would translate into real-life performance.

<comment><USER12> It's definitely not a realistic measure of overall language performance, but I think it certainly has value if taken with the right caveats. It's probably a reasonably good measure of function call overhead in different languages, and I think it's good for getting a better intuition about the order of magnitude difference to expect from, say, C vs JS (~3x slower than C in simple cases) vs Python (~100x slower than C).

<comment><USER6> > It's probably a reasonably good measure of function call overhead in > different languages

It's actually not. Fibonacci has a near-tail call in it that can convert some of the recursion into a loop. Furthermore, the runtime is dominated by useless recomputation that can be handled by memoization. So the distinction between languages is going to be dominated by their ability to do some moderately complex optimizations rather than by any intrinsic performance characteristics of their implementation.

Moreover, because the code is so small, there is likely to be major side effects as a result of effectively random differences--consider the effects of the code placement that cause a spurious difference between C and C++ kernels of about 20%. The JS version is going to get hit with a deoptimization at the very end (it might not impact performance) because the final result does not fit in an int32_t, and suddenly fib is no longer a well-typed function.

Microbenchmarking is _hard_, and it is all too easy for the microbenchmark to cease measuring the things that you want to measure.

<comment><USER13> Fibonacci (as implemented here) shouldn't be aided by any TCO. The execution trace will be something like:

      F(N) -- F(N-2) ...
       |
      F(N-1) -- F(N-3) ...
       |
      F(N-2) -- F(N-4) ...

But each has to return to the original caller because a summation still has to happen. The actual tail call is to the +/2 function.

F(N) can't complete until F(N-1) and F(N-2) have completed so it can sum up the values. If you pass the earlier computation, F(N-1), down to F(N-2) as a second parameter, you could get a tail call on the last part.

      fib(0, Val) -> Val + 1;
      fib(1, Val) -> Val + 1;
      fib(N, Val) ->
        T = fib(N-1,Val),
        fib(N-2,T).

(I think I wrote that correctly, can't test here.)

But that's a non-obvious tranformation. I really would like to see the compiler that recognized that this was a valid (computational) equivalent to the original.

<comment><USER6> But it is aided by tail-call optimization. Suppose you have a function as follows:

       int foo(int x) {
         if (test(x)) return C;
         return evaluate(x) + foo(adjust(x));
       }

I can turn that function into:

       int foo(int x) {
         int accum = C;
         for ( ; !test(x); x = adjust(x)) {
           accum += evaluate(x);
         }
         return accum;
       }

In the case of fibonacci, that equates to:

       int fib(int x) {
         int accum = 1;
         for (; x > 1; x -= 2) {
           accum += fib(x - 1);
         }
         return accum;
       }

We still turned the recursive call (or one of them, at least), into a while loop.

And this idiom is recognized by both gcc and llvm. In fact. llvm has a test that specifically makes sure fib is transformed as thus: [https://github.com/llvm- mirror/llvm/blob/30fa583f8430bfc7935...](https://github.com/llvm- mirror/llvm/blob/30fa583f8430bfc7935bf66b1aab50cfefd6cc11/test/Transforms/TailCallElim/accum_recursion.ll)

</comment></comment></comment></comment></comment><comment><USER14> I was intrigued to learn more about the winning language Nim to see how it beats C/C++, so I did a web search and was confounded to see Nim compiles to C/C++! What gives? Starting to doubt the methodology somewhat, though it was an interesting read.

<comment><USER15> Probably more about the difference between "echo" and "std::cout << ... << std::endl;" than the recursive function call.

<comment><USER16> I would be _very very_ surprised if printing "2971215073" accounted for more than 1 second of runtime.

<comment><USER11> Well, I know that printing stuff to console can be ridiculously slow, so this doesn't surprise me much.

<comment><USER16> An entire second to print 10 characters?! How does a terminal that slow even exist?

</comment></comment></comment></comment></comment><comment><USER17> Don't see the point really.

Languages without tail recursion will perform worse. Memoization is borderline cheating, because it's a different implementation.

Fib is the poster boy for tail recursion but the reason for that is that recursion to implement fib is simply a bad choice. It's cute but that's about it. If the point is to measure function call overhead, then measure _that_?

<comment><USER17> Just to underline the futility of this, if you are clever you can let the compiler do it.

[https://everything2.com/title/C%252B%252B%253A+computing+Fib...](https://everything2.com/title/C%252B%252B%253A+computing+Fibonacci+numbers+at+compile+time)

<comment><USER18> The benchmark includes a C++ constexpr version, at [https://github.com/drujensen/fib/blob/master/fib- constexpr.c...](https://github.com/drujensen/fib/blob/master/fib- constexpr.cpp) , with timing numbers under the section "Optimized code that breaks the benchmark" and the comment "all benchmarks will have some caveat."

</comment></comment></comment><comment><USER19> It would be interesting to include skip[1] as it has language level memoization. There was a recent HN discussion about the language [2]. I do not think that the naive recursive Fibonacci is a useful benchmark in any way though, it's a way too pessimized implementation.

[1] [http://www.skiplang.com/](http://www.skiplang.com/) [2] [https://news.ycombinator.com/item?id=18077612](https://news.ycombinator.com/item?id=18077612)

<comment><USER20> Why do we need language level memorization again? In python memoizing a function is just one line `@lru_cache()` I can't see why this needs an improvement by adding yet another thing to the core language.

<comment><USER21> Just adding a @lru_cache() to a python isn't guaranteed to be correct; for example, if you're reading from an API the response could change between calls.

Skip tracks side effects, and will either (a) memoize automatically a pure function or (b) recognize that a function is impure and avoid the memoization.

</comment></comment></comment><comment><USER22> During the my last technical interview, they asked my to write a fibonacci implementation in golang, i wrote the code, then they asked me to test it for like fb(180), i was surprised how slow it, then i was asked to come up with an optimisation in order to make it fast, i come exactly with same fib-mem.go provided in this benchmark, i was hired !

<comment><USER23> fib(180) without caching would take billions of years to complete, so "slow" is an understatement.

<comment><USER24> Or you write an iterative version of it that will not only be the simplest solution, it will be fast enough to compute fib(10000). There are constant time ones IIRC, but if someone comes up with such a solution in an interview without knowing it from before, they are probably over qualified for any job that uses the Fibonacci sequence as an interview question.

</comment></comment></comment><comment><USER25> Any matrix implementation (with fast exponentiation) is going to be much faster, even in a "slow" language. For instance, in ruby, `Matrix[[1,1],[1,0]] * * 46` is instantaneous (real time: 0.000131s).

We have to go up to the ten million'th term to get something that is not instantaneous (0.486s) for a result which has 2089876 digits.

<comment><USER26> Are you sure `Matrix[[1,1],[1,0]] * * 46` isn't optimized into a constant value by the bytecode compiler? Idk Ruby much, but it seems like a possiblity.

</comment></comment><comment><USER27> Nice to see the different implementations side-by-side. I do believe however that this is mainly a benchmark of startup time and initial JIT of the CRT/runtime/virtual machine/execution environment.

If you remove that time from the equation, I expect that the execution time will not differ a lot from each other.

<comment><USER28> Of all the benchmarks out there this is actually reasonable (though obviously limited). It runs the same thing in different languages and the processing time is long enough for VM startup not to matter.

Also the performance shows the bytecode languages C# and Java to do fairly well compared to C and GO.

<comment><USER29> That has mostly to do with the fact that the code isn't manipulating objects at all. As soon as you're starting pointer chasing in languages where almost everything is an object like javascript performance will suffer.

</comment></comment></comment><comment><USER30> SBCL on my 2012 Mac mini:

        rjmacmini:~$ sbcl
        This is SBCL 1.4.2, an implementation of ANSI Common Lisp.
        More information about SBCL is available at <http://www.sbcl.org/>.

        SBCL is free software, provided as is, with absolutely no warranty.
        It is mostly in the public domain; some portions are provided under
        BSD-style licenses.  See the CREDITS and COPYING files in the
        distribution for more information.
        * (defun fib (n)
            (declare (fixnum n)
                     (optimize (speed 3) (debug 0) (safety 0)))
            (if (<= n 1)
                1
              (the fixnum
                   (+ (fib (- n 1))
                      (fib (- n 2))))))

        FIB
        * (time (fib 46))

        Evaluation took:
          14.957 seconds of real time
          14.947616 seconds of total run time (14.934818 user, 0.012798 system)
          99.94% CPU
          38,799,794,836 processor cycles
          0 bytes consed

        2971215073
        * (SAVE-LISP-AND-DIE "/tmp/fiblisp" :toplevel (lambda (&rest args) (print (fib 46))) :executable t)
        ; in: SAVE-LISP-AND-DIE "/tmp/fiblisp"
        ;     (LAMBDA (&REST ARGS) (PRINT (FIB 46)))
        ;
        ; caught STYLE-WARNING:
        ;   The variable ARGS is defined but never used.
        ;
        ; compilation unit finished
        ;   caught 1 STYLE-WARNING condition
        [undoing binding stack and other enclosing state... done]
        [defragmenting immobile space... 643+15263+734+344+25029+16756 objects... done]
        [saving current Lisp image into /tmp/fiblisp:
        writing 0 bytes from the read-only space at 0x20000000
        writing 848 bytes from the static space at 0x20100000
        writing 1863680 bytes from the immobile space at 0x20300000
        writing 11472480 bytes from the immobile space at 0x21b00000
        writing 26542080 bytes from the dynamic space at 0x1000000000
        done]
        rjmacmini:~$ time /tmp/fiblisp

        2971215073
        real	0m14.785s
        user	0m14.755s
        sys	0m0.020s
        rjmacmini:~$

<comment><USER31> I don't think adding debug/safety 0 are really worth it. In this:

        (declaim (optimize speed)
                 (ftype (function (fixnum) fixnum) fib))

        (defun fib (n)
          (if (<= n 1)
            1
            (+ (fib (- n 1))
               (fib (- n 2)))))

        (print (fib 46))

adding `(safety 0) (debug 0)` took the time from 13.17s (with just the `speed` declaration) down to 12.94s for me. Is a 2% speed increase really worth the danger of `(safety 0)`?

<comment><USER30> Generally depends on the implementation and the default behavior.

But anyway, it's a good point.

</comment></comment></comment><comment><USER32> They should

\- remove the memoized versions (obviously it's faster)

\- show the executed instructions for each language of the main loop (which would be a nice exercise with all the vms and dynamic languages)

</comment><comment> ainar-g Re. Go.

I've turned this code into a Go benchmark and run it with both the default cmd/compile (1.11) and gccgo (8.2.0).

      cmd/compile:
      BenchmarkFib-4   	       1	16530409619 ns/op
      PASS
      ok  	command-line-arguments	16.533s

      gccgo:
      BenchmarkFib-4   	2	 776368644 ns/op
      PASS
      ok  	command-line-arguments	2.381s

So yeah, if you are doing heavy-weight math stuff in Go, you might consider switching to gccgo. You might get up to 20x performance boost.

Here is the gist, please tell me if I screwed up somewhere: [https://gist.github.com/ainar-g/1bd363d41c441d9ebf05c0c0b9f2...](https://gist.github.com/ainar-g/1bd363d41c441d9ebf05c0c0b9f2a529).

EDIT: After some disassembly and experimenting, it seems like what we see here is some clever unrolling and memoisation. If I change 46 from a constant to a variable, it becomes twice as slow. Plus there is this in disasm:

      /tmp/go/fibbench_test.go:13
              return fib(n-1) + fib(n-2)
          30b9:       e8 72 ff ff ff          callq  3030 <command_line_arguments.fib>
          30be:       bf 25 00 00 00          mov    $0x25,%edi
          30c3:       e8 68 ff ff ff          callq  3030 <command_line_arguments.fib>
          30c8:       bf 24 00 00 00          mov    $0x24,%edi
          30cd:       e8 5e ff ff ff          callq  3030 <command_line_arguments.fib>
          30d2:       bf 23 00 00 00          mov    $0x23,%edi
      ...

What puzzles me is why doesn't gcc do this for the C version. Even if I add an explicit __attribute__((const)).

<comment><USER33> So you're saying it would run in less than 1/4 of the time of the Nim, C, C++ implementations? Sure it's running the same algo?

<comment> ainar-g I am as confused as you are. The C version is much slower on my PC. I've added the link to the code above. Please tell me if you see something fishy.

</comment></comment></comment><comment><USER34> SBCL on my AMD FX(tm)-8350 Eight-Core Processor:

       ~$ sbcl
       This is SBCL 1.4.11, an implementation of ANSI Common Lisp.
       More information about SBCL is available at <http://www.sbcl.org/>.

       SBCL is free software, provided as is, with absolutely no warranty.
       It is mostly in the public domain; some portions are provided under
       BSD-style licenses.  See the CREDITS and COPYING files in the
       distribution for more information.
       * (defun fibonacci-tail-recursive ( n &optional (a 1) (b 1))
               (declare (optimize (speed 3) (safety 0) (debug 0))
                        (type fixnum n a b))
               (if (< n 1)
                   a
                   (fibonacci-tail-recursive (- n 1) b (+ a b))))

       FIBONACCI-TAIL-RECURSIVE
       * (time (fibonacci-tail-recursive 46))

       Evaluation took:
         0.000 seconds of real time
         0.000001 seconds of total run time (0.000001 user, 0.000000 system)
         100.00% CPU
         2,513 processor cycles
         0 bytes consed

         2971215073
       *

<comment><USER35> Different machine and superior algorithm, where are you aiming with this?

<comment><USER34> It's true, I only read recursive Fibonacci. Now I see my mistake.

<comment><USER35> That being said, this one [0] gives correct results and runs slightly faster :)

[0] [https://gist.github.com/codr4life/59f2c02403b27d551e706f673b...](https://gist.github.com/codr4life/59f2c02403b27d551e706f673bc50f15)

</comment></comment></comment></comment><comment><USER36> Several implementations are wrong -- they don't give the correct result.

<comment><USER37> They all seem to be consistently wrong. The series is shifted by 1.

</comment></comment><comment><USER38> Because Fortran was listed as x.xxx, I figured I'd try it. Taking the minimum of 100 runs of gcc/gfortran, 200 runs of g++, and 4 runs of Julia 1.1-dev:

gcc: 3.4866

g++: 3.4428

gfortran: 3.4953

Julia: 8.0378

I was doing other things while the benchmarks ran, which added noise. For the first run of g++, the mean was slightly higher than C's mean, while the standard deviation was much higher than C or Fortran's. So I reran it for C++, and then decided to just report the minimums for everything instead, because the minimum is probably the least biased measure _.

_ So long as there are no allocations that occasionally get cleaned up by a garbage collector. If there were, the GC cost should get amortized over all the runs that contributed to it. We don't have to worry about this here.

While the C and C++ assembly for the fib function was the same, Fortran's was different.

Julia's assembly was extremely brief in comparison, because it doesn't have any recursion optimizations -- it is just the check and then two calls to itself.

<comment><USER39> Yes, Julia doesn't do tail call optimizations (TCO) which it could do with LLVM. Just not enabled yet. I find it funny when people try to say that Julia's website benchmarks are cherrypicked to look good when the first example shows that it's tracking an optimization which it's missing...

</comment></comment><comment><USER40> One can improve the JAVA result by allowing the JIT compiler to inline the recursive calls.

       -XX:MaxRecursiveInlineLevel=1 (default): 6.667 s
       -XX:MaxRecursiveInlineLevel=2:           6.141 s
       -XX:MaxRecursiveInlineLevel=3:           5.768 s
       -XX:MaxRecursiveInlineLevel=4:           5.400 s
       -XX:MaxRecursiveInlineLevel=5:           5.361 s
       -XX:MaxRecursiveInlineLevel=6:           5.072 s

For comparison

       fib.c with -O3: 3.764 s

edit: formatting and adding more data points

</comment><comment><USER41> What's the point of even mentioning the memoized versions? OF COURSE the naive recursive version is slow and it's very easy to write something much faster in any language whatsoever.

</comment><comment><USER42> $ swiftc -Ounchecked -g fib.swift $ time ./fib 2971215073

real 0m6.341s user 0m6.297s sys 0m0.023s

Using unchecked mode is closer to what C is doing (skipping bounds and overflow checks).

</comment><comment><USER35> I would submit an entry for my own project, Snabl [0]; but it intentionally doesn't support the algorithm since naive recursion beyond a few levels doesn't make much sense in practice. I added a separate keyword to force tail calls since that's usually what you want.

[0] [https://github.com/codr4life/snabl#function](https://github.com/codr4life/snabl#function)

</comment><comment><USER33> A few observations:

\- on my machine, C++ is slower than C.

\- I thought that in Julia, startup and compile time could be a factor, but they're pretty negligible (maybe 1 to 5% or so of the runtime, for Julia 0.7).

\- Without the -O3 switch, the runtime more or less doubles for C and C++, making these languages slower than Swift, Go, Java, Dart, Julia, etc. That surprised me.

<comment><USER43> The -O3 switch removes a recursive call, among other things ([https://godbolt.org/z/oS3Cju](https://godbolt.org/z/oS3Cju)).

<comment><USER33> Interesting. (Awesome compiler explorer website, btw).

The Julia version (whose runtime is halfway between the C versions with vs without -O3) contains both recursive calls, FWIW.

</comment></comment></comment><comment><USER44> I decided to try this challenge using Solidity and made a little writeup comparing four implementations.

[https://medium.com/@jpa_of_snc/fibonacci-in- solidity-8477d90...](https://medium.com/@jpa_of_snc/fibonacci-in- solidity-8477d907e22a)

</comment><comment><USER45> As for me, these benchmarks are strange because there are solutions that are not omptimized -- in node.js implementation the memoized approach has been used (which outperforms the recursion), but in Java solution (as an example) -- the recursive approach has been implemented.

<comment><USER46> I think the intent is that the main implementations are those in files like `[Ff]ib.*`. There are additional memoized implementations for some languages, but presumably these are only used in the "Optimized code that breaks the benchmark" section.

</comment></comment><comment><USER47> Elixir can be made much faster via tail call optimization.

Something like:

      def fibonacci(n) when n >= 0, do: fib(0, 1, n)

      defp fib(a, b, n) do
        case n do
          0 ->
            a

          _ ->
            fib(b, a + b, n - 1)
        end
      end

<comment><USER48> There's a PR there to do just that. I don't follow the reasoning that it's not been accepted. It's also using Elixir script instead of precompiled Elixir.

[https://github.com/drujensen/fib/pull/33](https://github.com/drujensen/fib/pull/33)

<comment><USER47> Yeah, I don't think this breaks any of the rules. We are still using recursion. Just leveraging what the language has to offer.

<comment><USER12> The algorithm being benchmarked is the naive double-recursive fibonacci algorithm, which ends up performing over a billion addition operations in this case. The tail-recursive function above is the iterative bottom-up fibonacci algorithm that does it in about 50 addition operations. It's true that both use recursion, but the second is definitely not the tail-recursive version of the first.

It is possible to do a form of tail call optimization for the double-recursive algorithm, described here: [https://news.ycombinator.com/item?id=18096804](https://news.ycombinator.com/item?id=18096804)

This reduces the number of total function calls but not the number of additions (since it's not changing the algorithm, just the way the function invocation strategy when running the algorithm).

</comment></comment></comment></comment><comment><USER49> Something isn't quite right. Nim 'compiles' into C code ready for compilation. It should not be faster than the raw C and C++ implementation. Frankly even the C/C++ implementation shouldn't be so different.

</comment><comment><USER50> I think Rust also does not have tail call optimisation. Nim and Crystal I'd heard why relying on underlying compilers, and could sometimes fail to get it (perhaps more than you'd expect using a compiler more "directly"?).

</comment><comment><USER51> Sure but which languages are still there to calculate fib(100) and which bailed out?

</comment><comment><USER52> For Haskell try:

\-- Memorized variant is near instant even after 10000 memoized_fib :: Int -> Integer memoized_fib = (map fib [0 ..] !!) where fib 0 = 0 fib 1 = 1 fib n = memoized_fib (n-2) + memoized_fib (n-1)

or

fibM = \n -> values !! n where values = [fibAux m | m <\- [0..]] fibAux n | n <= 1 = n | otherwise = fibM (n-2) + fibM (n-1)

or

fibM2 :: Int -> Integer fibM2 = \n -> values !! n where values = [fibAux m | m <\- [0..]] fibAux 0 = 0 fibAux 1 = 1 fibAux n = fibM2 (n-2) + fibM2 (n-1)

Run the following at the ghci Haskell prompt:

memoized_fib 47

fibM 47

fibM2 47

If you want to wait try:

\-- Traditional implementation of fibonacci, hangs after about 30 slow_fib :: Int -> Integer slow_fib 0 = 0 slow_fib 1 = 1 slow_fib n = slow_fib (n-2) + slow_fib (n-1)

</comment><comment><USER53> The sport here seems to be which compiler manages to re-write the bad code best.

Tail call optimization is only marginally relevant here, since the tail call is the addition, not one of the recursions.

</comment><comment><USER54> I'd be interested to see how Elixir does with an OTP-optimised redo. Probably still not great, but I feel like the example isn't playing to its strengths.

<comment><USER55> The example was indeed not playing to its strengths, it wasn't making use of tail call optimization.

I made a PR to fix that: [https://github.com/drujensen/fib/pull/33](https://github.com/drujensen/fib/pull/33)

<comment><USER46> That's obviously a better choice if you actually want Fibonacci numbers, but it defeats the point of a benchmark if you implement a completely different algorithm in one of the languages.

</comment></comment></comment><comment><USER56> Does Zig get a mention? [https://godbolt.org/z/G0uvIU](https://godbolt.org/z/G0uvIU)

</comment><comment><USER12> It would be great to see webassembly on here as well! (Maybe hand-written and compiled from a few different languages.)

</comment><comment><USER57> Since we're talking about recursion, it would be neat to add benchmarks for languages that encourage recursion over iteration (not top 10, but could be fun):

\- Haskell

\- OCaml

\- Scala

\- F#

\- Clojure

\- Common Lisp

<comment><USER8> Haskell and OCaml have already been merged :)

</comment></comment><comment><USER58> A pretty fast way in Haskell/ghci[0] is:

λ: fibs = 1 : 1 : zipWith (+) fibs (tail fibs) λ: last $ take 47 fibs 2971215073

[0]: [https://wiki.haskell.org/The_Fibonacci_sequence#Canonical_zi...](https://wiki.haskell.org/The_Fibonacci_sequence#Canonical_zipWith_implementation)

<comment><USER59> It got mingled without newlines (and "λ:" prompt doesn't help readability). In one line:

let fibs = 0 : 1 : zipWith (+) fibs (tail fibs) in fibs !! 47

Shorter but less readable:

fix (scanl (+) 0 . (1:)) !! 47

</comment></comment><comment><USER60> What happened to the "Great Programminglanguage Shootout"?

<comment><USER4> Google can be your friend :-)

[https://www.google.com/search?q=Great+Programminglanguage+Sh...](https://www.google.com/search?q=Great+Programminglanguage+Shootout)

<comment><USER60> Yeah, I meant why is the project so quiet lately, and why doesn't HN refer to it more often.

<comment><USER4> Updates continue as usual:

[https://salsa.debian.org/benchmarksgame- team/benchmarksgame/...](https://salsa.debian.org/benchmarksgame- team/benchmarksgame/commits/master)

HN does refer to it:

[https://hn.algolia.com/?query=benchmarksgame&sort=byDate&pre...](https://hn.algolia.com/?query=benchmarksgame&sort=byDate&prefix&page=0&dateRange=pastYear&type=all)

As-always people crave novelty.

As-always it's easier to write simple 10 line programs rather than 100 line programs for 10 different tasks.

</comment></comment></comment></comment><comment><USER61> The rigth way to do fibonacci would probably be to add memoization...

<comment><USER62> Why not calculate it in constant time ?

[https://artofproblemsolving.com/wiki/index.php?title=Binet%2...](https://artofproblemsolving.com/wiki/index.php?title=Binet%27s_Formula)

<comment><USER63> You can't really compute it in constant time since the number of bits in the nth Fibonacci number is O(n), so you need to take at least that long just to write the result out.

Computing with Binet's formula is also rather tricky. You just need to round φ^n/√5, but how many bits of √5 do you need to use?

<comment><USER62> true: adding 2 64 bit numbers is constant time for me, but adding 2 4096 bit numbers is not. Eventually, even the simplest operation becomes O(ln n)

</comment></comment></comment></comment><comment><USER64> This is bullshit. IMHO, the recursive pattern is one of the worst constructs, this is really bad engineering and should not be used for benchmarking...

<comment><USER35> So you're saying never use recursion? Or never benchmark it? I don't get it, it's a tool; a pretty good tool when combined with tail call optimization. Yes, the algorithm they use is naive; I believe that's part of the point.

</comment></comment><comment><USER65> Why is python 2.7 faster than 3? I thought one of the big reasons to switch to 3 was because of performance

<comment><USER66> Where did you hear that? 3 hasn't even been competitive vs 2 until very recently.

Reasons for the switch have always been better Unicode handling and not being left behind as the community matches on (and soon lack of security updates to 2).

</comment></comment><comment><USER67> I'm just going to put this out there: this benchmark is silly, and only good for making languages with specific types of calling styles look good. It doesn't predict any real world performance. It doesn't speak to real world optimizer outcomes. It really just measures how shallow your call abstraction is. Several languages here perform much worse than equivalent code because the way the language interprets and executes naive recursion is different.

I've seen this game before, so the very first place I looked was the Haskell version. Sure enough, it doesn't even try to force the call graph at all. There's even a section entitled, "breaks the benchmark" and it doesn't note Haskell or other languages with different call semantics are not doing the same thing at all. It just says Haskell doesn't terminate.

Confusingly, there is then a "mem" benchmark which seems to ask "What happens if we do this with even the vaguest damn about algorithmic complexity?" But these are so all-over-the-map they don't even come close to measuring the same thing and have different memory usage.

What's frustrating about this is that the double-uncached is always the wrong way to write this code. It's never good, it really doesn't benchmark anything real world. It's not even a very good compiler benchmark because many optimizers actually go under the hood and rewrite code that is in this obvious style to be something else entirely, just to do better on these benchmarks.

For the Haskell benchmark as an example, the best way to to write this lazily is to write a function that consumes and drops a list like so:

        fibF n = head $ drop n fibs
          where
            fibs = 0 : 1 : next fibs
            next (first : rest) = (first + head rest) : next rest

        -- Or using a library function most Haskell Fp devs know.
        fibZip :: Int -> Int
        fibZip n = head $ drop n fibz
          where fibz = 0 : 1 : zipWith (+) fibz (tail fibz)

This is fast (it gets fused down to essentially a for loop in Haskell, and others like Javascript & Clojure can use this technique for a memory-efficient approach) it's very straightforward, and it's also _completely_ outside the world of something you can write naturally in C or Java (there is a natural Golang expression, but I don't see people using it).

This approach isn't even particularly fair to other languages that are _good_ at producing performant machine code, like Rust.

These games are not really indicative of anything. They waste energy. Folks should understand what their language runtimes and compilers are capable of, rather than asking, "How well does this fare on the worst possible algorithm for an operation who's semantics are only loosely defined?"

</comment><comment><USER68> isn't there supposed to be javascript results?

<comment><USER69> Its listed under "node"

<comment><USER68> oh i see, thanks

<comment><USER70> which is "broken" due to V8's optimizations unfortunately

</comment></comment></comment></comment><comment><USER71> so node 18 and python 500? really?

</comment><comment><USER72> Lua would probably outperform most languages on the list.

<comment><USER73> I couldn't find a list of the hardware used in the benchmarks, so comparing is difficult, though before testing, I'd lean towards agreeing with you. Luajit is often on par with C, D or Go.

However, as C was one of the faster, I'll use it as a comparison.

fib.c, compiled with 03: 10.49user 0.28system 0:11.62elapsed

        #include <stdio.h>

        long fib(long n) {
          if (n <= 1) return 1;
          return fib(n - 1) + fib(n - 2);
        }

        int main(void) {
          printf("%li\n", fib(46));
          return 0;
        }

Lua:

        function fib(n)
          if n <= 1 then
            return 1
          else
            return fib(n - 1) + fib(n - 2)
          end
        end

        print(fib(46))

Luajit: 48.66user 0.11system 0:52.95elapsed

Lua 5.3: 717.21user 8.40system 14:19.47elapsed

As Luajit was so much slower than C for this, which can be somewhat surprising.

Luajit would probably beat Ruby, for it's interpreted crown, but without optimisation, it won't beat the big boys.

I would say, that Lua isn't a good fit for solving this kind of problem, with these constraints, because every function call requires a hash lookup, which is irritating.

Of course, you could use Luajit's FFI to use C's implementation, which would be somewhat faster. Or expose the C implementation as a Lua library.

However, Lua is probably also a really good fit for memoization, and other techniques like that.

        local nums = {}
        local fib

        fib = function(n)
          if n <= 1 then
            return 1
          else
            if nums[n] then
              return nums[n]
            else
              nums[n] = fib(n - 1) + fib(n - 2)
              return nums[n]
            end
          end
        end

        print(fib(46))

This is a fairly naive implementation, but has the same final result as the previous examples... And 'time' is unable to measure how fast it is (Both Luajit and Lua5.3). For all intents and purposes, it's instant.

<comment><USER2> Hardware used is listed at the top of the readme. [https://github.com/drujensen/fib/blob/master/README.md](https://github.com/drujensen/fib/blob/master/README.md)

</comment></comment></comment><comment><USER74> I have a similar GitHub repo, but with a more complicated example:

[https://github.com/octonion/puzzles/tree/master/blackjack](https://github.com/octonion/puzzles/tree/master/blackjack)

</comment><comment><USER75> Using generators in Python you can do this much much faster :D.

        #!/usr/bin/env python

        """
        Calculate fibonacci numbers using a generator
        Usage: fibonacci.py [options] <N>

        Arguments:
            <N>             Print all Fibonacci numbers up to <N>-th

        Options:
            -h, --help      This help

        """

        from docopt import docopt

        def fibonacci():
            """generate fibonacci numbers"""
            a, b = 0, 1
            while 1:
                yield a
                a, b = b, a + b

        if __name__ == '__main__':
            try:
                args = docopt(__doc__)
                fib = fibonacci()
                for i in range(int(args["<N>"])):
                    print fib.next()
            except ValueError:
                print "You must specify valid integer"
            except KeyboardInterrupt:
                print "Good-bye"

You get something like

        $ time ./fibonacci.py 46
        0
        1
        1
        2
        3
        5
        8
        13
        21
        34
        55
        89
        144
        233
        377
        610
        987
        1597
        2584
        4181
        6765
        10946
        17711
        28657
        46368
        75025
        121393
        196418
        317811
        514229
        832040
        1346269
        2178309
        3524578
        5702887
        9227465
        14930352
        24157817
        39088169
        63245986
        102334155
        165580141
        267914296
        433494437
        701408733
        1134903170

        real	0m0.038s
        user	0m0.015s
        sys	0m0.018s

<comment><USER76> _Recursive_ fibonacci benchmark - you are doing something different in which case you could just evaluate the closed form φⁿ / √5 and be even faster.

<comment><USER75> I'm perfectly aware it's meant to be recursive, but it's also a completely pointless test. It's not tail recursive, so you are measuring function call overhead in various languages. But various languages have options to perform much faster anyway, but solution is of course going to be language specific.</comment></comment></comment>


A restored masterpiece unmasks Tokyo's underground gay subculture of the 1960s - <AUTHOR> http://bombmagazine.org/article/665269/toshio-masumoto-s-em-funeral-parade-of-roses-em <comment><USER2> this film is pretty great. i got it on video from a catalogue in the 90s (heard of it because one of the stars was in kurosawa's "ran").

if you like this, you would probably like shuuji terayama (of emperor tomato ketchup fame), those his work isn't the easiest to get in the USA outside of an academic context.

more available is nagisa oshima, a lot of whose work is on the excellent streaming service filmstruck, but it's a bit headier than bara no soretsu.

</comment><comment><USER3> Portland people interested, it just happens to be screening at the Hollywood tonight.

<comment><USER4> For SF people it's playing at the Alamo Drafthouse this weekend

</comment></comment><comment><USER5> Gender neutrality is currently trending in Harajuku. Source: BBC doc "Ryan Gander: The Idea of Japan" (now have to sign up to iPlayer though)

</comment><comment><USER6> This looks really interesting. I'm fascinated by gender dichotomy and how different my experiences would be with just a different chromosome.

<comment><USER7> "Just a different chromosome" can also give you Down's, if it doesn't outright kill you. It seems strange to use a diminutive to refer to a huge change in the genetic material that one's entire body is defined by.

<comment> jay-saint I think it is pretty clear that they are Talking about the Y chromosome, i.e. being born a different gender.

<comment><USER8> Yeah, they just had a bizarre way of saying it.

There's far less than one chromosome's worth of difference between me and a orangatan.

"Just a chromosome" is like saying "just an extra brain"

<comment><USER9> It can be pretty straightforwardly interpreted as a reference to the probability of being born into one gender or the other, which is roughly equivalent to a coin flip (not taking into account the higher chance of being born male, hermaphrodites, etc.)

<comment><USER10> It is roughly equivalent to zero. I as I am now couldn't be born with another chromosome.

Anyway, it could be interpreted as "If my parents had a girl instead of me, what it would be like to be she".

<comment><USER9> Isn't that what I wrote? I may not have expressed it clearly.

<comment><USER10> "Your parents could have had a different child", while true doesn't feel personal enough, doesn't it?

I don't like when correctness is sacrificed for emotional engagement.

<comment><USER9> I have trouble grasping why this distinction matters.

My understanding was that when people make "If I were X" statements, they are referring to having a conscious experience different than what they are currently experiencing. They would still be themselves by virtue of being the conscious observer in that context.</comment></comment></comment></comment></comment></comment></comment></comment></comment>


Can the Sharing Economy Get Us to Full Employment? - <AUTHOR> http://reesekyler.posthaven.com/can-the-sharing-economy-get-us-to-full-employment

<comment><USER2> I met a really interesting Lyft driver who drives 2 hours to San Francisco every weekend to drive 3 days of 12 hour shifts and then returns to her hometown to be a stay-at-home mom for the rest of the week days. Her husband also drives for Lyft part time and according to her, together they're making $100k more per year than they used to be and for the first time not living paycheck to paycheck anymore. It's inspiring stuff, but at the same time you have to consider that these people get no benefits, even if they were to drive full time, and have to front the costs of insurance, gas, and hotels in San Francisco to do what they're doing (because Uber etc. don't have enough volume in their small town). Providing people the opportunity to change their own lives like this just by working hard on their own schedule is huge, but also sounds like an opportunity for another startup (freebie!) to figure out how you provide these people with all the same benefits that they still need and make that as easy and affordable as it was when a company was providing it.</comment>