<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title>Pj's Pinnwand</title>
    <description>Pj's Pinnwand is similar to a blog except it isn't a blog because 'blog' is a lame word.</description>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#193</guid>
      <title><![CDATA[I'm starting to like this OccupyEverything.]]></title>
      <author>Pj</author>
      <pubDate>Wed, 26 Oct 2011 18:26:32 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/im_starting_to_like_this_occupyeverything.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I always thought it was a little interesting, but it seems to get more interesting as time goes on.<br><br>While the protesters started out not really knowing what they wanted, it seems that as time goes on, people are starting to think about everything.<br><br>Just the other day I read bunches of people on Slashdot talking about &quot;people don't need jobs, they need stuff&quot; and they also all rather agreed with Ron Paul's suggestion to eliminate federal student loans, both things that I mentioned in my previous post, and both things that I don't recall having ever heard anyone else talk about ever.<br><br>It's like everything I talked about isn't really beyond anyone's understanding, but rather, nothing has really prompted people to think about it and talk about it before now, and the Occupy Wall Street protests are changing that.<br><br>Do I have hope for the human race?  Hmm...<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#179</guid>
      <title><![CDATA[Politics: Debt]]></title>
      <author>Pj</author>
      <pubDate>Wed, 27 Jul 2011 17:02:00 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/politics_debt.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I almost hate writing about politics as politics sucks, but dammit...<br><br>We're presently in debt to the sum of $46,630 per person, or $130,042 per taxpayer.<br><br>Would you loan every person in the country $46,630, considering that 25% of them are children?  Would you loan each taxpayer in the country $130,042 considering that you know nothing about most of them?  <br><br>Even if you might loan some people $130,042, wouldn't you first check their financial status, making sure that there's a reasonable expectation that they'll be able to pay back the loan?  Make sure that they have a job, that they aren't already drowning in debt, stuff like that?<br><br>Indeed, wouldn't you insist on some collateral, perhaps the deed to the house they plan to buy with that money?<br><br>...or would you just loan them $130,042, no collateral necessary, based on the fact that they've always repaid their loans in the past?<br><br>Someone ran a nice scam in Second Life once.&nbsp; They set up ATMs promising a nice interest rate on deposits.&nbsp; As deposits came in, they were used to pay the interest on withdraws from deposits from the previous day.&nbsp; As people collected their interest, word spread, and popularity of the ATMs increased.&nbsp; It was a pyramid scheme.&nbsp; ...and like all pyramid schemes, it couldn't go on forever, and eventually people lost a lot of money.<br><br>What has the U.S. been doing?  We started by spending more money than we collect through taxes.&nbsp; To enable this, we borrowed some money.&nbsp; Then, as time passed, we paid interest on that money.&nbsp; However, we didn't raise taxes, and we didn't lower spending, so how did we pay that interest?  The money must have come from the additional borrowing we did.&nbsp; We pulled a World of Second Life ATM scam.&nbsp; Having never increased revenue to cover expenses, there's no way to say that the interest paid on our loans wasn't paid for with additional loans.&nbsp; <br><br>...and the world bought it.&nbsp; We have a perfect credit score.&nbsp; What's that based on?  It's based on the fact that we've never defaulted on a loan.&nbsp; ...and that's it.<br><br>Any sane investor is going to look closely at anything they invest in.&nbsp; When you get a loan for a house, they make sure that the house is worth what you're paying for it (so that the collateral covers the debt) and they make sure that your income exceeds your expenses so that they know you can make your payments.&nbsp; Similarly, anyone who might invest in Second Life ATMs might want to know how their business operates, and after seeing that it is a pyramid scheme, realize that it isn't something that can go on forever.&nbsp; Thus they might be excited if they're getting in on the ground floor, but if a lot of other people are involved already, they would do well to stay away.<br><br>So what to do about the debt crisis?  Personally, I think it's time to default.<br><br>People don't want to do that, of course.&nbsp; We've all been told that it's bad not to repay a loan.&nbsp; ...but having not repaid a credit card and a car loan, I've had some time to think about loans in general, and there's a real evil side to them that no one really wants to acknowledge.&nbsp; <br><br>I once had some friends ask me to loan them money to pay their rent.&nbsp; Neither had a job, having quit their previous jobs.&nbsp; Both were 18 years old, fresh out of their parent's house.&nbsp; So I said no.&nbsp; It would be stupid to loan them money when there was no reason to believe that next month they'd be in any better financial position than they were.<br><br>The logical thing for them to do would be to move out of their apartment and back in with their parents, thus reducing their expenses to match their income.&nbsp; ...and if they couldn't do that (but they certainly could have) they could move in with some friends.&nbsp; I told them they could move in with me if they had to.&nbsp; They eventually got the money from their parents, whom I presume probably felt it worthwhile to keep them out on their own.<br><br>That's the problem with credit.&nbsp; Without credit, there's a hard wall you run up against that says &quot;hey, dumbass, you're doing something wrong here&quot; and makes you stop and look at things immediately and figure out what is wrong.<br><br>When I got into debt, it wasn't in the stereotypical way, buying shiny new things just because I can.&nbsp; I got there buying stuff that I thought I needed.&nbsp; I ran up $4,000 on a credit card buying shit like food, a plunger, a shower curtain, and other typical household expenses.&nbsp; I also got a loan for a car, at an interest rate so high I would have done better to make ATM withdraws on my credit card.&nbsp; Truth is, I should have moved in with my mother (who previously moved out on me, and I chose to stay where I was).&nbsp; I should have fixed my old car rather than buy a new one, even if the new one wasn't anything special.&nbsp; (Indeed, I did later fix the car for far less than the cost of the new one, and it nearly outlived the one I bought.)  <br><br>I think most people get into debt this way.&nbsp; They aren't being irresponsible, they just don't know what they're getting into.&nbsp; I assumed that I needed the things I bought, as they were just typical stuff, and people are supposed to be able to get enough income to meet their expenses, so I assumed the two would eventually balance out.&nbsp; <br><br>Also, &quot;predatory lending&quot; doesn't help at all.&nbsp; Take the $1800 car I bought, for which I only needed $1650 of in a loan.&nbsp; After being turned down by two banks, I went to &quot;citifinancial&quot; or something like that.&nbsp; They told me they could offer me a 3 year loan with monthly payments of $120.&nbsp; That would include some insurance so that I only needed to get liability insurance.&nbsp; I'm not sure I even did as much as &quot;$120 x 3 years&quot; in my head to think about it.&nbsp; I thought about it no more than &quot;it's a loan, there's interest, that's how it works.&quot;<br><br>When the loan was complete, I got a pile of loan papers with it.&nbsp; I learned some things.&nbsp; The interest rate was 25%.&nbsp; I could have gotten 20% on my credit card with a cash advance.&nbsp; Seems that insurance wasn't a monthly payment either:  Instead they billed me for it all in advance so that they could charge interest on it as well.&nbsp; I never even looked into whether or not it was a fair rate.&nbsp; There was even $100 tossed in for a &quot;loan fee&quot; and maybe a few more things like that.&nbsp; In all, for my $1650 loan, I had a principle of $3000, nearly twice the amount, and at the worst interest rate allowed by law.<br><br>I'm sure a lot of people never even realize they've been screwed.<br><br>Now, popular opinion is that when someone gets a loan, they have a responsibility to make sure that the terms of the loan are fair, and that they can keep their agreement.<br><br>I'm not going to argue that's wrong.&nbsp; <br><br>What I disagree with is the other popular opinion, which is that those who loan others money are entitled to be repaid in all circumstances, even when, with a small amount of due diligence, they could have predicted the default well in advance of the loan.<br><br>After all, why should the person who obtains the loan be held to such a high standard of responsibility, while the creditor is free to hand out money to anyone under any circumstances, even if it might mean &quot;debt slavery&quot; if the debtor who can never pay down the principle, or even in the less severe case where the debtor can repay the debt but not without severe financial hardship?<br><br>Sure, people should be responsible, but people on both sides should be responsible.&nbsp; Those obtaining loans should ensure that they can repay them, and those offering loans should ensure that those they loan money to can repay the loans.<br><br>So when we have people making loans despite obvious knowledge that the loan makes no financial sense to the debtor, but instead simply hoping that they'll get enough interest on all of their loans to have some cash left over after absorbing the losses from the defaults, why should we care that the creditors aren't repaid?  After all, such behavior is no more responsible than people who get credit cards with no intention of repaying them, but instead simply planning to buy a bunch of toys.&nbsp; No one cares when those people get a bad credit score and can't get another credit card, so why should anyone care when bad lenders run out of cash and can't offer any more loans?  Both are simple matters of people hoping to make money on the ignorance of others, but getting what they deserve in the end.&nbsp; <br><br>Indeed, if those bad debtors go out of business, it probably won't be with massive losses, but rather, with a failure to make enough profit to stay in business.&nbsp; After all, once your profit falls below what you might get from a U.S. Treasury Bond, you might as well invest your money there instead and save yourself a lot of hassle.<br><br>So, think about all of this:  We're in debt up to $130,042 per taxpayer, and that debt is unsecured, not backed by any collateral, and yet we still find people to loan us money.&nbsp; ...and at an incredibly good rate as well.&nbsp; Divide our interest by our debt and we're paying about 1.5% per year.&nbsp; Who would loan more money to someone who is $130,042 in debt, none of which has collateral, and who also hasn't seen positive income in decades, indeed has no real plan to have a positive income in the future, and despite all of this, someone wants to loan us money at a 1.5% interest rate?<br><br>If that's not irresponsible lending, I don't know what is.<br><br>Yes, it was completely fucking irresponsible that the government ever got itself into this position, but let's not pretend as if our creditors are innocent.&nbsp; They're enablers.&nbsp; They weren't helping out a friend in a moment of hardship.&nbsp; They were &quot;helping&quot; a friend with an obvious spending addiction, funded by a pyramid scheme of loans, with no plan whatsoever of being more financially responsible in the future.&nbsp; ...and so how did they plan to be repaid?  Simply hoping to win their rewards from loans that other fools would offer us in the future?  Our creditors aren't innocent.&nbsp; They encouraged us to get into this mess by making it so easy for us.&nbsp; Any lender with the slightest bit of responsibility would have said no.<br><br>Defaulting is hardly the worst way we could solve this problem.&nbsp; So let's not pretend like it isn't an option.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#192</guid>
      <title><![CDATA[Politics: Occupy Wall Street &amp; the 99%]]></title>
      <author>Pj</author>
      <pubDate>Tue, 11 Oct 2011 07:45:34 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/politics_occupy_wall_street_the_99.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">It seems like everyone is complaining that the Occupy Wall Street protesters lack a common goal.&nbsp; They seem to have little in common other than that they all feel as if something is wrong.&nbsp; It's no surprise, really.&nbsp; If they knew what was wrong they might do something about it.&nbsp; ...and they can do something about it and they really don't even need to protest in order to do it.<br><br>There is a tumbler blog titled <a href="http://wearethe99percent.tumblr.com/">We Are the 99%</a> where people are posting their complaints.&nbsp; It does a wonderful job of showing what people are pissed about.&nbsp; It also shows that they have no idea what needs to change.&nbsp; Everyone can list what they think is wrong, but I see no suggestions on  how to make any of it right.&nbsp; People just feel that they're getting the short end of the stick and that's about all they know.<br><br>On the bright side, at least none of them think they know what needs to be done.&nbsp; People who know they are ignorant  are awesome.&nbsp; ...and I'm not being sarcastic.&nbsp; Sure, it'd be best if they knew what they want to change, however, since they don't, the fact that they aren't spouting random nonsense is absolutely the most anyone can ask.<br><br>So it isn't so much of a protest as it is a public demonstration of frustration.&nbsp; People seem to think there's something wrong with that.&nbsp; I say it may be a little pointless, but there's certainly nothing wrong with it.<br><br>Anyway, since I think I know everything, I also think I know what these people are pissed about.&nbsp; Maybe I should explain so that they can finally know what the hell they want to change.&nbsp; I'm not sure there is any point, as it's been my experience that no one ever agrees with my political ideas, but, what else am I going to do today?<br><br>So, I'll try.&nbsp; Not sure how we'll I'll do since, despite being all rather simple, it's nevertheless difficult to explain since everyone is so far away from understanding.&nbsp; Particularly anyone who doesn't understand that there's more than a liberal and a conservative viewpoint.&nbsp; Each is likely to think that I'm way too much like the other.<br><br><h2>People don't need jobs.</h2><br>Jobs are necessary as a practical matter, but it's important to remember that, ultimately, we don't need jobs.&nbsp; Instead, we need food, shelter, medical care, etc.<br><br>Obviously people want jobs because jobs will earn them money and they can buy the things they need with that money, but it's important to remember this rather obvious fact.&nbsp; It's relevant when people start talking about there not being enough jobs to remember that giving people jobs doesn't necessarily give people what they need if they still aren't able to get food, shelter, and medical care.<br><br>Keep this in mind next time the government suggests solving problems by creating jobs.&nbsp; Repaving roads which don't require repaving is just like the broken window fallacy.<br><br><h2>Money isn't wealth.</h2><br>Wealth, in simple terms, is having what you want.&nbsp; While money makes it easier to get what you want, it's important to remember that it isn't money, but instead &quot;what you want,&quot; that everyone wants.&nbsp; <br><br>Thus, while everyone wants to be rich, no one really cares about being rich.&nbsp; We only want the things we want, and we only want a lot of money because it is the easiest way we can imagine to get the things we want.&nbsp; (Indeed, money is essential to getting what we want, since it is how the free market keeps production in proportion to demand, however, people ultimately have no need for stacks of paper.&nbsp; Money is just a means to an end.)<br><br><h2>Money represents human labor.</h2><br>Imagine a world with two people.&nbsp; Each wants something done that the other can do.&nbsp; It would make sense for them to each do something for the other.&nbsp; They might even create a form of currency to represent how much each has done for the other, somewhat like &quot;I own you one.&quot;  The currency serves as a measurement of how much work each has done relative to the other.&nbsp; When one does an hour of work for the other, he is paid another unit of currency.<br>  When one runs out of currency, he can't get the other to do anything else for him until he does something for the other in order to earn back some of that currency. <br><br>This applies even with the value of property, assuming everyone has access to natural resources.&nbsp; (or at least that enough people have access to natural resources)  For example, if one person finds a stick and carves it into a spear, the value of the stick is the amount of labor that went into it, since the other can just find his own stick and carve it himself.<br>  Thus, if the price of that spear is less than the value of the labor that went into it, the person who created the spear feels cheated, and if the price is more than the value of the labor that went into it, the person buying the spear feels cheated.<br><br>Now let's throw a few thousand other people into this imaginary world so that we can have an economy.<br><br>Imagine several people are carving up sticks into spears and selling them.&nbsp; A few people might be particularly good at this, enabling him to carve them faster than the others.&nbsp; Thus, when they sell the spears, they're essentially paid a little more than the others.<br><br>Eventually those who are good at carving spears might decide to lower their prices in order to capture more of the market.&nbsp; This forces those who aren't good at carving spears to also sell theirs for less.&nbsp; Thus they get less money for their labor.&nbsp; So they decide to do start carving forks instead, since no one is good at carving forks and so they can be adequately compensated for their labor if they carve forks.<br><br>Then someone else gets clever and builds a machine to create spears from sticks, allowing him to create ten spears with the same amount of labor that everyone else uses to create one spear.&nbsp; Suddenly he's paid a lot more than the others.&nbsp; So he charges a bit less for his spears, forcing everyone else to lower their prices well below the value of the labor they put into creating their spears.<br><br>However, rather than also create forks, the others decide to build their own machines.&nbsp; To regain more market share, they too reduce their price to be a little below the price of the first person.&nbsp; Then he reduces his price.&nbsp; This continues until the price again reflects the amount of human labor that goes into producing the spears.&nbsp; <br><br>The reason for this is simple:  If the people making the spears are forced to lower their price so much that they can get more money for their labor by doing something else, they'll go and do something else.&nbsp; Until the price is that low, however, they can always make their price lower in order to take a larger share of the market from their competitors, earning more money by making up in volume what they lose by selling for a lower price.&nbsp; <br><br>Thus, money represents human labor.&nbsp; When machines start doing things for people, less labor is involved and prices go down.&nbsp; Then we can buy more things for the same amount of money.&nbsp; Thus we get more of &quot;what we want&quot; and we all become more wealthy despite having no more money than we had before.<br><br>Another important thing to notice at this point is that no-one is as yet &quot;making a good salary.&quot;  They're all making a fair salary, both the people with the spear-carving machines, and the people hand-carving forks, as no one has figured out how to build a fork-carving machine yet.<br>  Spears are cheap, forks are expensive, and the difference is only due to the human labor involved.<br><br>Now, those who were fast at carving spears, they were making a good salary for a while.&nbsp; Sort of.&nbsp; They might have been making 20% more than the average person.&nbsp; However, a lot of people don't think you're doing good until you're making 100% more than the average person.<br>  Some people won't be happy until they're making several times what the average person makes.<br><br>However, there's a problem with earning so much more money than the average person:  There's a natural limit to how much better someone can be at doing something than someone else is.<br><br>Granted, that isn't always the limiting factor.&nbsp; If you absolutely want the best sports player on your team, you might have to pay him twice what the second-best player is paid, simply because someone else is willing to pay him almost as much, and it isn't a reasonable substitute to hire twice as many players who are half as good, since only so many can play on the team at the same time.&nbsp; However, this assumes that you're determined to have the best team possible, perhaps because you want to win.&nbsp; If instead you're simply interested in watching a good game, choosing players outside of the top 100 who you can hire for far less would make a lot of financial sense, since the quality of game that you see will likely be quite similar as long as you play your team against similarly-skilled teams.&nbsp; Thus, such out-of-proportion salaries can only occur where there is a demand to have the best rather than to settle for the very good.&nbsp; Not many markets function that way.<br><br>Usually you can simply hire twice as many people who are half as good.&nbsp; Maybe A and B only work half as fast as C, but if C wants you to pay him more than what you would pay A and B combined, you'd do better to just hire A and B and politely tell C to go fuck himself.<br><br>Thus, money is generally a representation of human labor.&nbsp; I'm not saying that there aren't exceptions, but it is generally true.<br><br><h2>For one person to become slightly rich, another must become slightly poor.</h2><br>This idea is surprisingly controversial for some reason.<br><br>However, it's a natural consequence of &quot;money represents human labor.&quot;  Everyone as a whole produces a certain amount of product.&nbsp; You want a larger share of that product without doing a larger share of the work?  How else do you think that is going to happen?<br>  <br><br><h2>College degrees don't magically produce money.</h2><br>“I went to college so I earned a larger share of the results of human labor!”  Well, no, you haven't earned it until you've worked to produce it.&nbsp; Some of that work was done in college when you learned whatever you needed to do your job, so yes, you will be paid more, but you won't get more than your fair share.<br><br>Since college costs time and money, people won't do it without an expectation of a larger salary.&nbsp; So your employer will have to pay you more.&nbsp; However, to expect that salary to be more than necessary to compensate you for your studies and college tuition is to expect too much.&nbsp; <br><br>Remember that whole “supply vs. demand” thing?  The more that a job pays, the more people will be willing to put the work and money into college to get those jobs.&nbsp; The result will be a larger labor pool, which will mean that people will have to compete to get those jobs.&nbsp; Thus people will have to work for less, eventually being forced to work for just enough to compensate people for the time and money they spent in college.&nbsp; Only then will people stop being interested in paying for college.<br><br>So to get out of college and find that you're forced to work for a salary that you barely find to be worth the effort of having attended college is actually the expected case.&nbsp; That's how the free market works.&nbsp; The free market doesn't allow situations to exist where people can get a lot of money for little work.<br><br><h2>The free market doesn't allow easy high-paying jobs to exist.</h2><br>It's obvious if you think about it.&nbsp; Where easy high-paying jobs exist, everyone will decide to go.&nbsp; This increases the labor market for that job.&nbsp; Thus people have to be willing to work for less to get that job.&nbsp; This continues until the pay for the job is in proportion to the amount of labor that goes into it.&nbsp; At that point, people stop seeking this particular job and go elsewhere.&nbsp; <br><br>You can see this in large cities, where you can find the same job as elsewhere but offering a higher salary.&nbsp; Then you get there and find that your cost of living is also higher.&nbsp; The jobs only pay more because they have to in order to compensate people for living near enough to perform that job.&nbsp; Otherwise they'll move somewhere with a lower cost of living.<br><br><h2>There are few legitimate ways to become incredibly rich.</h2><br>It's the only logical conclusion from all of the above.&nbsp; <br><br>You may be able to become more wealthy than other people in a legitimate way.&nbsp; People can always work 80 hours a week instead of 20.&nbsp; Also, some people are naturally more intelligent than others, and so whatever they decide to do, they'll do it better than others, and thus will be able to create more with the same amount of labor than others can create.&nbsp; However, there are limits.&nbsp; There are only so many hours a person can work in a week.&nbsp; Also, working more intelligently can only get you so far.&nbsp; <br><br><h2>However, there are still legitimate ways to become rich.</h2><br>One obvious way is to win the lottery.&nbsp; Everyone who played knew damn well that they were probably just giving their dollar to you.&nbsp; The rules are simple and offer no one an advantage (except perhaps those intelligent enough not to play).&nbsp; If you win, you didn't do so by trickery.&nbsp; Indeed, you (who won) and everyone else (who lost) were indistinguishable in terms of your involvement until one of you won.&nbsp; Thus, winning the lottery is likely the most legitimate way to become rich.<br><br>Another way is to find yourself into one of those situations where the demand for the best is significantly greater than the demand for the second-best.&nbsp; Sports teams are an example, since team owners want to win games, and will pay 10% more for a player that is only 1% better.&nbsp; Another example is likely CEOs, where being second-best might mean that your company fails to adequately compete with the competition.&nbsp; That is, assuming you really are the best person for the job.&nbsp; It's always possible that you simply got the job because of who you know, and thus, the salary isn't legitimate at all.<br><br>Also, there's always the possibility of getting lucky.&nbsp; You may be a moron, but even a stopped clock is correct twice a day.&nbsp; Perhaps your moment is a very lucky one and happens to earn you a lot of money.&nbsp;  It's unlikely, but it isn't impossible.&nbsp; <br><br>So there are a few legitimate ways to become rich.&nbsp; However, they're few enough that you shouldn't expect any of them.&nbsp; You're not going to win the lottery.&nbsp; You're also likely not the best in the country at whatever you do.&nbsp; ...and even if you are, it likely isn't one of those fields where having the best is significantly better than having the second-best, in which case you won't earn a ridiculously high salary.<br><br><h2>So how do people become so rich?</h2><br>Well, it's obvious.&nbsp; If there aren't many legitimate ways to become rich, then simply choose an illegitimate way.&nbsp; Work-at-home schemes are popular and quite successful since they play on people's desires to earn easy money.&nbsp; It also helps a lot that public education promotes the idea that anyone can become wealthy through hard work, and thus people assume that if they work hard, they too can have a $500,000 house and three nice cars.<br><br>Also, there are plenty of illegitimate yet legal ways to become rich.&nbsp; For example, you might invent a clever device to make a table saw blade come to a sudden stop if it ever comes into contact with human flesh, thereby greatly minimizing injury.&nbsp; Thus, by itself, is a very nice thing, but then to ensure you become rich, you might patent the invention, then lobby some politicians to create a law requiring such a device in all table saws that are built, essentially legislating that everyone who makes a table saw pay your patent royalties.&nbsp; Thus, you become rich, since no one has a choice but to either give you money or stop building table saws.&nbsp; You sure are clever!<br><br>Another good way to become rich is to sell things to people who have too much money.&nbsp; One prime target is the government.&nbsp; Just build some piece of shit, like an electronic voting machine, at a time when there's a lot of talk about some poorly functioning mechanical voting machines.&nbsp; Then see how many fools you can get to buy the thing.&nbsp; While it's easy to get a fool to part with his money, the problem is that fools usually don't have any money because they've already parted with it.&nbsp; However, the government is an exception to this rule.&nbsp; Lately they've been running a pyramid scheme known as “u.s. government bonds” giving them a virtually unlimited amount of money.&nbsp; So just sell your garbage to those fools.&nbsp; Then you'll become rich.<br><br>You can also become rich via trickle-down economics.&nbsp; To do this, you build something that generally isn't all that great.&nbsp; Perhaps a small computer contained in a portable flat-panel touch-screen display.&nbsp; You might make it in China, but then cover it with feel-good statements like “designed in California” so that people feel like they're buying something of higher-than-usual quality.&nbsp; Then market the hell out of it.&nbsp; The result will be that everyone who is overpaid, a happy result of working for those who are illegitimately earning money from the government, will want your device, and happily pay the far-more-than-its-worth that you're asking for it.<br><br>However, perhaps the most effective way is to loan money at high interest rates.&nbsp; This is easy to do since everyone has a desire to have a nice house and a nice car, and they've been told all of their lives that everyone should be able to afford these things.&nbsp; Thus everyone is looking to borrow money.&nbsp; Also, few of them received any education in high school about making intelligent decisions with regard to accepting loans, and they certainly learned nothing about predatory lending practices. There's always a risk they'll declare bankruptcy, but that's what collateral is for.&nbsp; ...or you can just offer student loans which aren't allowed to be dismissed with bankruptcy.&nbsp; Best case you earn a lot of interest.&nbsp; Worst case you have to repossess something and sell it to get your money back.&nbsp; The best thing about this is that you don't even have to have money to loan money.&nbsp; You can just get the federal reserve to print some up for you.&nbsp; Granted, you can't default on that loan, but between collateral and bankruptcy-ineligible student loans, paying it back shouldn't be a problem.&nbsp; Then you get to keep all of the interest. <br><br>You might also offer credit cards.&nbsp; You can't get much money through interest, and there's a lot of bankruptcy involved due to lack of collateral, but you can make your money back with merchant fees.&nbsp; The merchants will pay the fees because they won't want to risk losing sales, and you can prevent anyone from seeing the real cost of your credit cards by refusing to do business with any merchant who doesn't spread the fees equally among all customers whether they use credit cards or not.&nbsp; The result is that everyone who makes a purchase anywhere is giving you some money, even when they use cash.<br><br>There really are a lot of ways to become rich.&nbsp; It's all just a matter of how good you want to feel about yourself at the end of the day.<br><br><h2>So should we make the rich pay more taxes?</h2><br>That is debatable.<br><br>On the one hand, there aren't many legitimate ways to become rich, so most of those who are rich didn't get their money by any legitimate way to begin with.&nbsp; However, there are a few who did legitimately become rich.&nbsp; However, most of them didn't work harder than other people for their money anyway, but rather, just happened to be born with the right genetics to become the best at something.&nbsp; (Which isn't to say that they didn't work hard.&nbsp; Obviously there are people with good genetics, and there are people who work hard, and there are people who both have good genetics and work hard, and it is those who become the best.)  However, there are also those who become rich by hard work alone.&nbsp; Surely it wouldn't be fair to make them pay a larger share of taxes.<br><br><h2>So we shouldn't make the rich pay more taxes?</h2><br>Well, funny thing about all of those illegitimate ways to become rich...&nbsp; They require the cooperation of  the rest of us.<br><br>For people to become rich by starting work-at-home schemes requires that the rest of us fail to make work-at-home schemes illegal.&nbsp; <br><br>For people to become rich by selling garbage to the government requires that we allow the government to continue to hemorrhage money.&nbsp; This requires that we continue to allow it to operate it's pyramid scheme of acquiring more loans in order to have enough revenue to repay its previous loans plus some extra to make up for expenditures being greater than income.<br><br>As for those corporations exploiting virtual slaves in China to sell you overpriced garbage, just stop buying it.&nbsp; No one is forcing you to.<br><br>As for predatory lending, just stop getting loans.&nbsp; Warn your friends and family about the cost of loans.&nbsp; <br><br>As for credit cards, there isn't much you can do about retailers giving your cash to the credit card companies, but you can definitely stop using your credit card at retailers.&nbsp; Just go to your bank's ATM before you go to the store and withdraw from your checking account.&nbsp; That's one less transaction the store has to pay the credit card company for, so while you're still paying the credit card company even though you use cash, you're paying ever so slightly less.&nbsp; If enough people do it, you're paying a lot less, and the merchant may drop credit cards altogether.<br><br>So, we could make the rich pay more taxes, since most of them didn't get their money legitimately.&nbsp; Or we could avoid over-taxing those who are legitimately rich simply by not going out of our way to give our money to those who are illegitimately becoming rich.<br><br>Don't want someone to have a lot of money?  Don't give them your money.&nbsp; Obviously some laws will have to be changed, but as we already have a progressive tax rate that makes the rich pay more than the poor, we don't really need to go further than that.&nbsp; ...and even if we did, it wouldn't be nearly as effective as simply not giving money to the rich to begin with.&nbsp; We can virtually tax them 100% simply by not giving them the money to begin with, which is better than taking back 50% of it afterwards.<br><br><h2>Universal Healthcare</h2><br>Healthcare is also a common concern mentioned on the 99% blog.&nbsp; <br><br>I'm sure I've tried to say it before, but I'll try again:  Nothing makes more sense than universal healthcare.<br><br>Insurance is about paying small amounts to cover a large expense that may not happen.&nbsp; A good example is cancer.&nbsp; Not everyone gets cancer.&nbsp; For example, lets say that 10% of people can expect to get cancer.&nbsp; By all agreeing in advance to pay for everyone's cancer treatments, everyone can pay just 10% of the cost of treatment while ensuring that they don't have to pay any more than that should the be unlucky to get cancer.&nbsp; ...and for those who were unlucky enough to pay for healthcare they didn't need?  Well, I'm sure everyone wishes they could be so unlucky as to not get cancer.<br><br>Insurance doesn't make sense for things that you know are going to happen.&nbsp; A good example (were not not for something I'll discuss later) is regular doctor visits.&nbsp; You know that you'll need a dental checkup once every six months.&nbsp; To buy insurance for it would only serve to give the insurance company some money in order that they give some of it back to pay for your checkups.<br><br>Also, insurance makes more sense before your risk for some disease is known.&nbsp; Imagine, for example, that some test is developed that determines with great accuracy whether you are one of those 10% of people who will eventually get cancer.&nbsp; One of a few things will happen:<br><br>1.&nbsp; Getting insurance for cancer will require the test.&nbsp; If you will get cancer, you'll have to pay 100% of the cost for treatment in order to get insurance.&nbsp; Thus insurance won't make sense, except for the fact that you still don't know when you'll get cancer.&nbsp; You'd essentially be paying “now vs. later” insurance, and thus if you didn't get cancer until later, you'll pay double the cost of treatment in insurance premiums, to balance for the people who got cancer the day after obtaining coverage.<br><br>2.&nbsp; Some law will prevent insurance providers from requiring the test.&nbsp; However, they'll still assume that you've had the test.&nbsp; You'd be a fool not to get the test, since it tells you whether you need the insurance or not.&nbsp; So the insurance companies will assume you will get cancer and still charge the high rates.<br><br>3.&nbsp; Some law will make the test entirely illegal.&nbsp; This will make the insurance affordable, however, it will also prevent a valuable warning of a potential and serious disease.<br><br>Thus, for insurance to work at all, there is a requirement for some uncertainty as to whether or not you will get the disease.<br><br>However, most people don't get to choose whether to get insurance until they are old enough to get a job.&nbsp; At that point a lot is already known about their health.&nbsp; Thus two things happen:<br><br>1.&nbsp; Those who have many health problems don't really benefit from insurance.<br><br>2.&nbsp; Those who don't have many health problems are tempted not to get insurance.<br><br>The obvious solution to all of this is to insure everyone at the moment of conception.&nbsp; Indeed, even before conception, as there are genetic conditions in which it is known that children will be at an increased risk for some disease.&nbsp; While it's true that the parents should exercise some caution and not burden the world with diseased children, I think it's also true that we shouldn't blame children for having stupid parents.&nbsp; So to rely on parents to properly insure children at the moment of conception is irresponsible.<br><br>So why not universal coverage?  The simple fact is that there really is no one who doesn't want health insurance.&nbsp; We can argue about freedom, but who is really going to choose to just roll over and die if they unexpectedly get cancer at a young age?  Virtually no one except perhaps the clinically depressed who probably also need some other healthcare.<br><br>So insure everyone.&nbsp; ...and since we're insuring before we know anything about anyone's health, everyone pays the same share.&nbsp; It's really quite simple and logical.<br><br>It's like police coverage.&nbsp; Sure, you could get “police insurance” to cover your police needs, but everyone needs protection from crime and so we might as well per-emtively insure everyone and just collect the premiums through taxes.&nbsp; <br><br><h2>So what should the 99% demand?</h2><br>1.&nbsp; Better education.<br><br>Stop teaching kids that they can simply work hard and become rich.&nbsp; The free market doesn't allow it to happen.&nbsp; It only sets them up for disappointment.&nbsp; I know teachers love education, but it isn't magic.&nbsp; It can't change the reality that some kids will have to grow up to collect the garbage for the rest, nor can it make it likely that any of them will become rich.&nbsp; <br><br>Teach kids about economics, loans, and in particular, teach them about scams.&nbsp; In fact, “Scams” should be a fucking class all by itself.&nbsp; Perhaps even two classes. Would you prefer your kids know how to spell or would you prefer that they know better than to involve themselves in any work-at-home scam?  Would you prefer that they spend a year analyzing classic literature or would you prefer that they not only know how to calculate the cost of a loan, but that they understand that doing so is a requirement of not getting shafted by a lender?  I guess some might say that the kids need more “street smart” rather than “book smart.”  There's no reason why they can't get their “street smart” while they're in school.<br><br>2.&nbsp; Fewer scams.<br><br>Obviously we need more laws against much of the shit which is presently tolerated.&nbsp; The department of homeland security should be refocused on pretty much anything that is advertised on television that isn't food.&nbsp; ...and don't forget all of the work-at-home offers in the newspaper.&nbsp; People lose money on worthless diet pills every day, the only result being that someone becomes richer while everyone else gets less than what they deserve for the work they've done.&nbsp; Misleading people for the purpose of collecting their money shouldn't be legal just because of something in the fine print.&nbsp; Indeed, comments like “not everyone will be successful” are complete lies when the truth is “virtually no one will be successful.”  This stuff shouldn't be legal.<br><br>3.&nbsp; Universal healthcare.<br><br>The fact that virtually everyone on the 99% blog mentions healthcare says it all.&nbsp; A system that depends on people being healthy enough to earn money to pay premiums is broken by design.<br><br>4.&nbsp; Same government service, less government spending.<br><br>If your personal budget is thin, it'd be nice if you could just cut something out of it since that would be a quick and easy solution, but it's quite likely you're already not paying for anything that you don't want.&nbsp; So you usually can't cut things entirely in order to save money.&nbsp; Yet that is the only thing that politicians want to do.<br><br>Instead you look for waste.&nbsp; Is your electric bill too high?  Well, you can turn off the electricity, or you can turn things off when you're not using them, turn down the thermostat, turn off the AC, seal cracks in the windows, turn off some lights, etc.&nbsp; Even buy a Kill-a-Watt for $20 at Home Depot and have it tell you how much every damn thing in your house costs to run.&nbsp; It's a lot more work that way, but at least you get to make intelligent decisions about what to keep and what to cut rather than hacking away blindly.&nbsp; Worst case you might buy some insulation and seal off half of your house so that you can pay only half as much to heat the half you live in.&nbsp; However, you don't just turn off the electricity.<br><br>Reducing costs is rarely as easy as finding some large expense you can cut or greatly reduce.&nbsp; (...but we likely have an exception with the military.)  Usually you have to find small ways to reduce the cost of everything so that they add up to big savings.&nbsp; Who hasn't heard the story of some government department finding things to waste the remainder of their budget on at the end of the year because if they don't spend it then their budget will be reduced next year?  It would seem that we might save some money all around if we can put a stop to shit like that.<br><br>One huge area for savings is the ministry of peace.&nbsp; It only wastes money to constantly manufacturer new and better weapons we'll never use just to replace the older weapons we also never used.&nbsp; Just ally ourselves with other peaceful nations and rely on the fact that, between all of us, we'll have enough to take out the lunatics should they attack any of us.&nbsp; How many days did we need to take over Iraq?  ...and that's the process of invading another country.&nbsp; For actual matters of defense we'd have the upper hand due to the conflict being on our home turf.&nbsp; Anyone we might need to defend ourselves against isn't all that strong.&nbsp; To spend so much on defense makes no sense at all.&nbsp; ...and let's not even talk about the “war on a few lunatics who got lucky that one time.”  If the world becomes a more dangerous place, it won't happen overnight.&nbsp; We'll have some warning to start building up our military again.<br><br>5.&nbsp; Better consumer protections.<br><br>Credit card companies shouldn't be allowed to tell retailers how much they are allowed to charge their customers.&nbsp; If retailers want to pass on the cost of credit card transactions only to those who use credit cards, they should be allowed to do so.&nbsp; Then people can see just how much of their money is going to their credit card company.<br><br>If your bank is going to pay for your free checking account by charging ridiculous fees when you accidentally overdraw your account due to their &quot;deposits not available until end of the next business day unless you deposit after noon in which cause they're not available until after the end of the business day after the next business day&quot; policy, they should be forced to mention that sort of shit rather clearly when you open the account.&nbsp; <br><br>When people apply for loans, it should be a requirement that they are informed of the total cost of the loan, including all interest and fees.&nbsp; <br><br>Most everything presently advertised on television should be considered an illegal scam.<br><br><h2>What shouldn't the 99% demand?</h2><br>I've outlined the problems above.&nbsp; None of those problems will be solved by increasing the taxes on the rich.&nbsp; (Not that I care to comment on whether that should be done, as such a comment would require sorting fact from shit that I've heard, which I don't care to do.&nbsp; I care only about all of the other shit I've mentioned.)<br><br>Also, while I admit I hardly know shit about how corporate taxes work, I fail to see how any income taxes for corporations is a good thing.&nbsp; I don't see how they could do anything other than guarantee that only the companies with the sleaziest tax practices become the largest companies in the country, due to being the companies with the most cash on hand to expand their business.<br><br>The demand for corporations to pay income taxes just seems to be a failure of having a logical plan for taxation, much like taxing people with both income taxes, sales taxes, and a variety of other taxes isn't all that logical.&nbsp; Much the same, it's probably just another way to raise taxes on individuals without appearing to raise taxes since, as corporations are made of people, those taxes are ultimately payed by people anyway.&nbsp; <br><br>As I said above, money is a representation of human labor.&nbsp; Thus corporations pay taxes with human labor.&nbsp; To think that corporation taxes aren't just human taxes in disguise is absurd.&nbsp; People pay those taxes because people are the only source of money.<br><br><h2>...and what should the 99% do?</h2><br>First of all, they shouldn't buy anything without looking around for the lowest price.&nbsp; <b>Especially medical care</b> as it's one of our largest expenses due to the fact that absolutely no one shops around for the lowest price, short of finding someone who will accept their insurance.&nbsp; I recently learned that a cheap dentist costs only 25% of what an expensive one costs.&nbsp; ...and that was just between the two I visited.&nbsp; I can't imagine what I'd find if I looked for the most expensive and the least expensive to compare.<br><br>The simple fact is that x-rays are ancient technology, but unless you ask around for prices rather than simply going to whichever lab your doctor points you towards, there's no incentive whatsoever for the price to be anything less than astronomical.<br><br>Always ask for prices before you obtain any service.&nbsp; You can never assume you'll be charged a fair price because the moment you stop asking is the moment you'll get raped.<br><br>Stop obtaining loans for shit.&nbsp; Especially houses and cars.&nbsp; Do you know why houses and cars are so expensive?  A lot of it is because people don't have to pay for these things immediately.&nbsp; When you can just get a loan, you don't have to think about just how fucking much money $100,000 is.&nbsp; Thus sellers have less incentive to offer reasonable prices.&nbsp; <br><br>Cars are similar.&nbsp; Inexpensive yet new cars exist for those who look for them.&nbsp; They'd likely be even less expensive if there were more demand for them.&nbsp; ...but, since you're getting a loan, you might as well opt for the power windows and every other feature which is priced for far more than it costs.&nbsp; Why is it priced for more than it costs?  Because you want it.&nbsp; <br><br>The goal is to get as much money from each customer as possible, regardless of how much money that customer has.&nbsp; So inexpensive cars with no options are offered near the price it costs to produce them.&nbsp; Then options are added, all very basic things like a modest stereo and electronic door locks, but these options are all priced for more than they cost to produce.&nbsp; In that way, the more you can afford to pay, the more profit the car company makes, but in the case that you don't have much money, the car company still gets whatever profit it can from you since it still sells you a car.<br><br>Lower your expectations.&nbsp; Much of the reason people feel so poor is that they have such high expectations.&nbsp; We have well-insulated houses, computers, internet, telephones, television, and so much food that most of us have become obese, yet we think we're lacking somehow.&nbsp; We also can't find jobs, yet farmers say they can't hire anyone other than illegal immigrants.&nbsp; Who, by the way, seem to be rather happy working jobs we don't want while living with ten roommates in a three bedroom house and trying to stay hidden from the police.&nbsp; Yet we're upset because we thought that by going to college we'd be guaranteed a well-paying job, yet we can't find one, and won't take one that isn't well-paying in the meantime, and we're barely scraping by while posting on Facebook all day and apparently having plenty of spare time to wander around Wall street as they apparently aren't busy looking for a job.&nbsp; No, let's not do anything like pick up a few roommates if we can't afford rent.&nbsp; We can't lower our standards by having less than one bedroom per individual.&nbsp; No way.<br><br>However, I can't say I blame anyone.&nbsp; I don't want to share my bedroom with anyone.&nbsp; Indeed, if I could afford it, I wouldn't share my apartment with anyone.&nbsp; Even if it meant that I'd have to constantly bitch and whine that I can barely afford my rent.<br><br>That, however, is the ultimate problem.&nbsp; No matter how much money you have, you can always find something else to want.&nbsp; Our society is built around want.&nbsp; ...and given that no one really wants money, but instead we want stuff, it's only natural that we have no money because we're spending it all on stuff.&nbsp; Whether that be things that are easy to give up like cell phones or video games, or something that's more difficult to give up like an apartment that we don't have to share with anyone, we all have shit that we could give up if we really had to.&nbsp; That's why so very few of us are living on the streets.&nbsp; We may all think that we are just barely scraping by, but if that were true, we'd have a lot more homeless than we do.<br><br><h2>TL;DR</h2><br>The 99% should demand less bullshit, but we should realize that a portion of that bullshit is our own decisions and expectations.&nbsp; Yes, we're being fucked by the rich, but at the same time, we are bending over while they stand behind us.&nbsp; Perhaps we should stand up and turn around.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#187</guid>
      <title><![CDATA[Adventures in Signal Processing]]></title>
      <author>Pj</author>
      <pubDate>Wed, 14 Sep 2011 09:18:51 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/adventures_in_signal_processing.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Seems my apparently-inept attempt at 60 Hz filtering altered that frequency response graph I made.&nbsp; So I replaced it with one made without filters.&nbsp; Also, this one was created with an automated script, so there's a data point for each integer Hz, except 60 which I removed due to local interference.&nbsp; <br><br><center><img src="http://www.ecstaticlyrics.com/pinnwand/messages/stuff/zfr.png"></center><br>Anyway, I started to wonder if I couldn't use this data to remove the filtering.&nbsp; Obviously, after doing a discrete Fourier transformation, I could scale the results by this data to calculate what the unfiltered results would be, but I wondered if I could go one step further and reassemble the waveform to reveal what it looks like before filtering.<br><br>Filters do two things to frequencies:  One, the obvious, is that they attenuate frequencies by some factor dependent on the frequency.&nbsp; That is what is measured in the graph above.&nbsp; The other thing they do is alter the phase of the frequency, again, the amount being different for each frequency.&nbsp; So I set out to measure that phase shift.&nbsp; <br><br>First I tried creating a sudden pulse, then introducing the waveform at a fixed time after the pulse.&nbsp; This worked, but was obviously less effective at higher frequencies where minor timing errors resulted in large phase errors.<br><br>Next I tried combining the frequencies under test with a 1 Hz frequency.&nbsp; I then measured the phase of both frequencies over a ten second period, then calculated the phase of the frequency under test relative to the phase of the frequency of the 1 Hz reference.&nbsp; This too worked, but I discovered that the Zeo's sampling rate isn't exactly 128 Hz.&nbsp; Mine appears to drift around 127.5 Hz.<br><br>So, finally, I tried something much like the above, but instead I sampled only for one second, then average together a minute's worth of these samples.&nbsp; The result is that the amplitude seems to be accurate to +/- 0.1 µV, and the phase seems to be accurate to +/- 1° at 10 Hz, at least judging by how much jitter there is in the average that gets displayed each second.<br><br>So, what kind of results do I get for my work?  Well, the results are far from perfect, but given how seemingly correct they are, I think I might be dangerous if I actually knew something about signal processing.&nbsp; <br><br>First, a simple sine wave, at 1 Hz, 100 µV.&nbsp; Here's a picture of what it looks like as presented by the Zeo, with only some 60 Hz filtering applied to make it visible:<br><br><center><img src="stuff/unfilter/sine-1-before.png"></center><br>...and here's what it looks like after being processed by my &quot;unfilter&quot;...<br><br><center><img src="stuff/unfilter/sine-1-after.png"></center><br>As you can see, the amplitude is now perfect.&nbsp; However, sine waves are simple.<br><br>A real challenge is a square wave.&nbsp; A 1 Hz square wave is composed of a 1 Hz sine wave, a 3 Hz sine wave at 1/3 amplitude, a 5 Hz sine wave at 1/5 amplitude, and so on.&nbsp; Additionally, for it to be a square wave, the phase of all of those sine waves must be in perfect alignment.&nbsp; Otherwise it looks completely different.<br><br>Here is a 3 Hz square wave before being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/square-3-before.png"></center><br>...and here is the same 3 Hz square wave after being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/square-3-after.png"></center><br>A sawtooth wave is composed similarly to a square wave, but uses every integer multiple of the base frequency instead of only the odd multiples.&nbsp; <br><br>Here is a 1 Hz sawtooth wave before being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/saw-1-before.png"></center><br>...and here is the same 1 Hz sawtooth wave after being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/saw-1-after.png"></center><br>A 1 Hz triangle wave before being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/triangle-1-before.png"></center><br>...and the same 1 Hz triangle wave after being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/triangle-1-after.png"></center><br>Fucking sweet, right?<br><br>Well, it's not all so sweet.&nbsp; The thing quite obviously tosses out incorrect waveforms at times.&nbsp; Here's an example, using a 1/4 second pulse surrounded by 4 seconds of nothing, after going through the &quot;unfilter:&quot;<br><br><center><img src="stuff/unfilter/pulse-after.png"></center><br>Note the way that the line curves downward in anticipation of the pulse, and does the opposite on the other side.&nbsp; <br><br>Still, it's much better than it looked before being &quot;unfiltered:&quot;<br><br><center><img src="stuff/unfilter/pulse-before.png"></center><br>...but, even so, that's not the worst I've seen come from it, just a simple and convenient example.<br><br>I'm rather undecided whether or not this is a good thing.&nbsp; On the one hand, the output looks so much better than the input in a lot of cases, but at the same time, I'm hardly feeding it real-world waveforms.&nbsp; Real-world waveforms may not benefit so well from processing.&nbsp; ...but then, maybe that pulse (and some other junk I've seen come out all wrong) is so unnatural that the defect it reveals is irrelevant.<br><br>...but, whatever.&nbsp; I've fucked with this long enough, time to start trying to make a new EEG.<br><br>Anyway, this seems like the perfect candidate for my new anti-viral license, so...<br><br>Download: <a href="stuff/unfilter/unfilter.c">unfilter.c</a><br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#167</guid>
      <title><![CDATA[The game that is not called mooscraft.]]></title>
      <author>Pj</author>
      <pubDate>Thu, 17 Mar 2011 09:49:24 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/the_game_that_is_not_called_mooscraft.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">If you don't know what <a href="http://www.minecraft.net/">Minecraft</a> is, it's basically this:<br><br><center><img src="stuff/game-images/play.jpg"></center><br>You're this little person who wanders around this 3D world with nothing better to do than build things.&nbsp; So that's what you do.&nbsp; Then someone else comes along and builds a giant swastika on the side.<br><br>After writing my own server and effectively-enough solving the problem with griefers, I began to develop a long list of stuff about the game that annoys me.<br><br>Number one was the rendering perspective.&nbsp; If you look at something straight ahead, it looks one size.&nbsp; Then turn so that it's at the side of your view, and suddenly it's twice as large.<br><br>Number two was the fog, specifically the way that it wasn't circular around the player position, but based only on z-depth into the field of view.<br><br>Then there were the block types in the game.&nbsp; They mostly suck, as the color selection is a painful array of what Phaelonimaire accurately describes as &quot;faggot purple&quot; and of the non-color blocks, only a few are really useful for building anything that looks nice.&nbsp; ...and the most annoying aspect of this is that it would be so easy to add more block types to the game, but it'll never happen.<br><br>Then there's the game scale, or lack thereof.&nbsp; Depending on what you use as cues, you get a different sense of scale for the game.&nbsp; Go by the height of the player, and the blocks are about one meter in size.&nbsp; Go by the size of the bricks on the brick block, and the blocks are about 0.4 meters in size.&nbsp; Go by the size of the planks on the wood blocks, you again get something else.&nbsp; Size of the books on the bookcase block?  Maybe the size of the TNT sticks in the TNT block?  Or maybe you'd like to judge by running speed, or the acceleration when the player falls to the ground from up high?  There's no limit to the number of ways you can arrive at a different feel for the scale of the game, and the result is that everyone builds at a different scale, and everyone's creations look out of whack to half of everyone who looks at them because they see the game at a different scale.&nbsp; <br><br>Then there's the chat.&nbsp; Messages are limited to 64 characters, minus the length of the player's name, and usually minus another 4 characters for color codes.&nbsp; Then the chat is rendered in a scaled-up low-res font, with only a displacement rendering of the text below it as a poor shadow which barely does anything to make the text more readable.&nbsp; Check it out in the top left corner of the image above.&nbsp; When people want to chat in the game, they have to go find a solid color to look at while they read the chat text.&nbsp; ...but most annoying is the 50-or-so character limit, too short to fit even a full sentence.<br><br>Then there's the mouse button assignment.&nbsp; The game uses left click to destroy blocks, right click to create blocks.&nbsp; It's the reverse of what any sane person would expect.&nbsp; Even the instructions below the game describe the reverse assignment, claiming that left click creates blocks.&nbsp; Left click usually creates things, but not in Minecraft.&nbsp; It took me three full days of playing the game before I stopped trying to use left click to create blocks.&nbsp; As best I can guess, destroying blocks was the first thing added to the game, so it got the main mouse button, then when the ability to create blocks was added, the developer was already too used to destroying with left click, so create went on right click.&nbsp; What's more, I still suspect that much of the problem with people joining the game and doing nothing but destroying stuff is from people clicking the button they usually use and not figuring out how to do anything else.<br><br>However, what bothered me most about the game was that its popularly was completely in spite of itself.&nbsp; Take Notch's server from his web site and run it for a while.&nbsp; You end up with a server map that is flooded, random holes everywhere, and a forest of single-block-wide towers.&nbsp; This happens for a few reasons:  <br><br>Most importantly, Notch's server has only retroactive access controls.&nbsp; You can kick people and ban people, but any new random person automatically has build permissions.&nbsp; So you can ban someone who misbehaves, but a new random person will follow along shortly.&nbsp; <br><br>Another factor is the difficultly of moving around with Notch's client.&nbsp; People log into a server and it's a bit of a mess and they wonder if there's anything there.&nbsp; So they build a tower to get up high to look around.&nbsp; Then they see nothing but garbage, and log out, leaving the tower.&nbsp; Then more people follow along and do the same.&nbsp; <br><br>If it were only Notch's server, no one would play Minecraft.&nbsp; The only reason the game is popular because of all of the work done by independent developers to create servers with useful access controls, and some other group of people who created a hack for the game client to allow people to fly around and walk through walls.&nbsp; <br><br>So, it all rather pissed me off.&nbsp; Here Notch was with a game that was extremely popular, which he was getting millions of dollars from, despite the fact that everything people really liked about the game was someone else's work.<br><br>It really made me want to write my own client to go with my server.&nbsp; It'd be so easy to fix the problems mentioned above, if only programming weren't such a pain in the ass.<br><br>Then Phaelonimaire came to the rescue by researching how to use OpenGL and finding some useful examples I was able to learn from.&nbsp; With that I was able to create a rendering engine in all of about two days.&nbsp; Since then we've spent the last four or five months working on this thing, whenever each of us doesn't feel like shit and can work on it.<br><br>So far, we have this:<br><br><center><img src="stuff/game-images/house.jpg"></center><br>This is a house I built, using blueprints I found in the internet which I then drew a grid on according to the map scale, then built in the game.&nbsp; I went through such effort because one of my priorities with this game is scale.&nbsp; I want all of the textures at the correct size.&nbsp; I want the player's walking and running speed to be correct.&nbsp; When the player falls, I want the time to hit the ground to be the same as it is in real life.&nbsp; ...and it is.&nbsp; A fall of 10 meters takes 1.42 seconds, and the whole time you're accelerating at a steady 9.8 meters per second squared.&nbsp; So anyway, for further testing, I needed a perfectly scaled house, hence the building from blueprints. <br><br>The game presently has like 182 block types plus another 58 or so solid color blocks.&nbsp; They're arranged into categories in a menu like this:<br><br><center><img src="stuff/game-images/colors.jpg"></center><br>Note the small number of &quot;faggot purple&quot; colors.&nbsp; At first I tried choosing colors according to a certain number of bits per color channel, but that created the same horrific color space Minecraft has.&nbsp; Then I researched better color spaces, then tried choosing equally distant colors in a L*a*b* color space, but that too looked like shit.&nbsp; So I just thought about the problem for a while, looked at what people were doing with the color blocks, and decided to manually choose a few common colors and include a gradient of each, from dark to light.&nbsp; The result is quite popular with the sprite-building players.<br><br>The other textures in the game are shit, downloaded from a &quot;free textures&quot; web site.&nbsp; I really want to photograph my own textures, in order to get the kinds of textures I want, but most importantly so that I can incorporate each texture into the game at the correct scale.&nbsp; The ones currently in it are only approximately to scale, since I couldn't find any textures web site which seemed to think that texture scale was important, so the best I could do was to look at each texture and make a guess.&nbsp; I really can't wait to lose those textures and replace them with my own, but it'll require a few days with a lot of energy and a lack of winter to get some good photos.<br><br>Here's a sample of the rendering of the chat text:<br><br><center><img src="stuff/game-images/text.jpg"></center><br>I found a free true type font on the internet, which I then rendered into a graphics program to add a shadow, then saved as an image file.&nbsp; I'm quite happy with the result, and in fact now and then I try to use that true type font for something else, but it just looks worse outside the game.&nbsp; ...but most importantly, the text is easy to read, despite the random background it is rendered against.&nbsp; I've never desired to find something different to look at in order to read the text more easily.&nbsp; It's amazing what a proper shadow can do.<br><br>I was unable to find any OpenGL menu libraries I liked, and so I created my own:<br><br><center><img src="stuff/game-images/menus.jpg"></center><br>It has the standard stuff:  check boxes, radio buttons, clickable text, etc.&nbsp; At first I had no idea how I was even going to code this, but now, it's sweet.<br><br>Of interest on that menu is the &quot;perfect perspective&quot; option.&nbsp; If you get the monitor close to your eyes, then input the measurements, it will set the rendering perspective so that what is drawn in each part of the screen is what you would see there if the screen was a window into the 3D world.&nbsp; It's actually not a good thing if the monitor is far from your face, but if your can get close enough that your face is closer to the screen than the height of the window, you end up with a very realistic feel as you move around, and things feel like they really are as large as they are in the game.&nbsp; <br><br>I actually got the idea for that from Minecraft, when trying to figure out what was with it's warped rendering perspective.&nbsp; I eventually determined that the field of view was 70 degrees vertically, and that that field of view was correct if my face was three inches from the monitor.&nbsp; So I put my face three inches from the monitor and played for a while, and it was quite amazing how realistic it was.&nbsp; I then decided that my game had to have such an option, to input your screen size and distance in order to create such an accurately-sized rendering.<br><br>Another cool feature is the &quot;map wrap&quot; option, which does away with the ends of the map by wrapping the ends together, so that you can walk continuously in one direction and just keep seeing things over and over again.&nbsp; It's done in such a way that it isn't obvious where the ends come together.&nbsp; There's no break in the rendering, no sudden jump from one side to the other, you can even build a house right over the spot where the two haves come together and it will look the same as if you'd built it anywhere else.<br><br>Here's a view of map-wrap enabled on my server's map.&nbsp; The map isn't intended to be wrapped, so the edges don't align, but you can still see how the two sides are joined as one:<br><br><center><img src="stuff/game-images/wrap.jpg"></center><br><br>It's really unfortunate how many months it's been and yet this game still isn't finished.&nbsp; I keep hoping to find the cure for my lack of energy, since it always feels like a finished game is just a month away if I could work on it every day.<br><br>However, on the bright side, this gives me something to do.&nbsp; When I feel well, I work on the game, when I don't, I simply play around with it, which as far as low energy things to do go, it beats the hell out of reading Slashdot.&nbsp; It's also somewhat social since there are other people in the game too, and those people are less annoying since they aren't the Slashdot type.&nbsp; Even without any sort of release there are already about 15 people playing it: some of the more intelligent people from my Minecraft server, several of my nephews, and their friends at school.<br><br>If ever the game is finished, I don't think it'll have any problem being popular.&nbsp; At present I haven't told many people about it since it wasn't until yesterday that there was a server with anti-grief measures, but after someone at my nephews school found out about the game and began destroying things, I &quot;ported&quot; my Minecraft server to the game, to provide a safe place for people to build things.&nbsp; <br><br>...but now that there's some anti-grief, even if only on one of the servers, I guess I can post a URL out in the open now.&nbsp; ...that is, if you want to believe that anything on my blog is really where anyone is going to see it.<br><br><a href="http://moosfet.nfshost.com/game">http://moosfet.nfshost.com/game</a><br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#188</guid>
      <title><![CDATA[Sleep Study Results]]></title>
      <author>Pj</author>
      <pubDate>Wed, 21 Sep 2011 17:54:58 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/sleep_study_results.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">On Wed, 24 Aug 2011 14:06:16 -0400, Gray, Joyce &lt;jegray@gshdayton.org&gt; wrote:<br> <br><div class="block">UARS has still not gained as much recognition as it should.&nbsp; Our medical director, Dr. CN Reddy, is actually exceptional at the recognition and treatment of UARS.</div> <br>I nearly didn't bother to make an appointment, as I haven't a lot of energy and I didn't have much reason to expect a positive outcome, but receiving this reply was very encouraging.&nbsp; So I came to your sleep center.<br> <br>I was a little surprised that there wasn't a Pes sensor involved in my sleep study, but I'd read on PubMed about nasal cannulas being used to diagnose UARS by looking at the pressure waveform for indications of airflow obstruction.&nbsp; It's actually rather obvious once you know what to look for.&nbsp; I've <a href="stuff/small_image.png">attached a small image</a> as an example, a sample from my own recording of my respiration during my sleep.&nbsp; The way that the normally semi-sinusoidal waveform becomes clipped on the top indicates restricted airflow on inhalation, indicating the presence of the &quot;upper airway resistance&quot; in &quot;upper airway resistance syndrome.&quot;  Then, after arousal (which I have verified with EEG), the waveform goes back to being semi-sinusoidal.&nbsp; Indeed, it's so easy to spot, one wonders why doctors ever resorted to using a Pes sensor, as it certainly doesn't sound as if one would be comfortable at all.<br> <br>Here are a couple of free full-text articles I found on PubMed if you care to read about it:<br> <br><a href="http://www.ncbi.nlm.nih.gov/pubmed/10767242">http://www.ncbi.nlm.nih.gov/pubmed/10767242</a> -- Quote: &quot;...inspiratory flow contour analysis has been shown to accurately identify changes in upper airway resistance.&nbsp; The shape of a normal inspiratory flow vs time signal is rounded or sinusoidal. A flattening or plateau of this morphology implies flow limitation, which is characterized by a nonlinear relationship between airflow and driving pressure secondary to increased airway resistance.&quot;<br> <br><a href="http://www.ncbi.nlm.nih.gov/pubmed/9603124">http://www.ncbi.nlm.nih.gov/pubmed/9603124</a> -- The third image in this article shows a waveform that looks remarkably similar to the image I've attached, which is from a recording of my own respiration during my sleep.&nbsp; Thus you can certainly see why I believe I have UARS.<br> <br>I brought with me a printout of my respiration recording and showed it to Dr. Reddy.&nbsp; He seemed to have no idea that the flattened waveforms indicate anything at all.&nbsp; Instead he only saw smaller respiration waveforms interrupted with normal breathing and concluded it to simply be periodic breathing.&nbsp; So, rather than recognize it as UARS, Dr. Reddy instead concluded that I awoke 46 times and slept only 53% of the night for apparently no reason whatsoever.<br> <br>Without a Pes sensor, and without knowledge of what those clipped waveforms indicate, I fail to see how Dr. Reddy can diagnose UARS at all, let alone be exceptional at it.<br> <br>Anyway, I'm sure you didn't mean to be dishonest in your initial response.&nbsp; You, and indeed everyone I met at the sleep center, seem to care a lot.&nbsp; I can't even fault Dr. Reddy, as I've done enough research on the subject myself to realize that the odds are against me to ever have this diagnosed.&nbsp; The history of sleep research has unfortunately set things up in such a way that the symptoms of UARS are nearly by definition non-clinical.&nbsp; However, this whole experience has consumed time, money, and energy I didn't really have, something I was trying to avoid with my initial inquiry.&nbsp; So, I must say, I am rather disappointed.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#202</guid>
      <title><![CDATA[...but GCC is pretty good at integer code.]]></title>
      <author>Pj</author>
      <pubDate>Thu, 5 Apr 2012 18:20:36 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/but_gcc_is_pretty_good_at_integer_code.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I eventually realized that since I don't care about the actual distances, but only what is further than what, that I don't actually need the sqrt(), as comparing the squared values will work just as well.&nbsp; <br><br>That allowed me to reduce it to purely integer math, which cut the C version down from 16 ms to 1.7 ms.&nbsp; <br><br>So I did the same thing with my assembly code, but it still took 2.1 ms.&nbsp; Checking out GCC's code, I saw that it made an optimization by calculating dx outside of the inner loop.&nbsp; Clever GCC, I hadn't thought of that.&nbsp; So I adjusted my code accordingly.&nbsp; It still seems my code is a bit slower, but it's hard to judge since there's some variability in timing between runs.&nbsp; Averaging more trials doesn't help because for some reason the variability is constant per invocation of the test program.&nbsp; It'll do 100 runs of 2.1 ms, then I immediately run the program again and see it do 100 runs of 1.8 ms.&nbsp; It must be ending up in different memory or something, I guess.<br><br>Anyway, after spending hours upon hours debugging the assembly code I wrote for the sort function, I now have an assembly language version that runs in 63 ms vs. GCC's version which runs in 53 ms.&nbsp; I didn't even bother to examine GCC's code this time, as I've wasted enough hours on my assembly language version already.&nbsp; So fuck it.&nbsp; GCC wins, both in speed and in reduced effort in writing and debugging the code.<br><br>I just wish it would compile floating point stuff more efficiently than it does.&nbsp; I'm so tempted to create something which you put a set of formulas into and it generates an assembly language stream of floating point instructions that you can compile to perform those calculations.&nbsp; It'd be like, a compiler, but only for math.<br><br>As for the minecraft server, I don't know that I want to blow 61 ms on this.&nbsp; I think I'll just keep thinking about it for a while and see if I can think of a better way to do it.&nbsp; (Like maybe writing a server for my own game, which doesn't have stupid lag problems, making all of this irrelevant since I can just send the block changes when they occur.)<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#204</guid>
      <title><![CDATA[-ffast-math, fesetround(), and nearbyint()]]></title>
      <author>Pj</author>
      <pubDate>Fri, 6 Apr 2012 13:41:41 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/ffast_math_fesetround_and_nearbyint.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I really don't want to do assembly anymore.&nbsp; Last time I was doing assembly I had created a set of NASM macros that allowed me to specify names for my function parameters and local stack-based variables.&nbsp; I then realized I had a C compiler, just with a different language syntax.&nbsp; It worked for me, since I found C's syntax repulsive, but I've since grown used to it, so it doesn't bother me anymore.&nbsp; Thus I'd rather stay away from assembly if I can.&nbsp; Especially since I lost the patches I had to make to NASM to make my macros work, and although I sent them to the NASM author, he rejected them, and spoke of his own ideas for an even better set of macros, which last I checked (which was years afterwards) hadn't materialized in the current version.<br><br>So if I can find a way to make GCC generate the code I want, then I'm fine with that.&nbsp; Writing C code is a lot faster and easier than writing assembly code.<br><br>Anyway, I decided to look into this some more, and I thought that, with all of GCC's compiler options, maybe there's something that deals with this.&nbsp; So I searched a little and found <tt>-ffast-math</tt>.&nbsp; <br><br>Without that option, code like &quot;int x = floor(y)&quot; turns into shit like this:<br><br><div class="block"><pre><font color="red">  08049524  83EC24            sub esp,byte +0x24</font><br>  08049527  DD4508            fld qword [ebp+0x8]<br><font color="red">  0804952a  DD1C24            fstp qword [esp]<br>  0804952d  E87EF8FFFF        call dword 0x8048db0 floor@plt</font><br><font color="blue">  08049532  D97DF6            fnstcw [ebp-0xa]<br>  08049535  0FB745F6          movzx eax,word [ebp-0xa]<br>  08049539  B40C              mov ah,0xc<br>  0804953b  668945F4          mov [ebp-0xc],ax<br>  0804953f  D96DF4            fldcw [ebp-0xc]</font><br>  08049542  DB5DF0            fistp dword [ebp-0x10]<br><font color="blue">  08049545  D96DF6            fldcw [ebp-0xa]</font><br><font color="red">  08049555  83C424            add esp,byte +0x24</font><br></pre></div><br>The instructions in red are the ones necessary to call round().&nbsp; They set up room on the stack for the parameter, put the parameter on the stack, call the function, then remove the space from the stack at the end.&nbsp; The instructions in blue implements GCC's standard &quot;round towards zero&quot; when storing floating point values to integers.&nbsp; (which is why it's necessary to call floor() explicitly rather than simply storing the value to an integer)  These instructions store the current floating point control word, modify its flags to round towards zero, then at the end, restore the previous flag settings.&nbsp; In all, only the two instructions in black are actually required to perform the operation, assuming you already have your floating point control word set up for the style of rounding you prefer.&nbsp; <br><br>...and, if that wasn't enough of a disaster, here's the dump of the floor() function:<br><br><div class="block"><pre><font color="blue">  00008e40  DD442404          fld qword [esp+0x4]</font><br><font color="red">  00008e44  83EC08            sub esp,byte +0x8<br>  00008e47  9BD97C2404        fstcw [esp+0x4]<br>  00008e4c  BA00040000        mov edx,0x400<br>  00008e51  0B542404          or edx,[esp+0x4]<br>  00008e55  81E2FFF70000      and edx,0xf7ff<br>  00008e5b  891424            mov [esp],edx<br>  00008e5e  D92C24            fldcw [esp]</font><br>  00008e61  D9FC              frndint<br><font color="red">  00008e63  D96C2404          fldcw [esp+0x4]<br>  00008e67  83C408            add esp,byte +0x8</font><br><font color="blue">  00008e6a  C3                ret</font></pre></div><br>Here, the instruction at the top retrieves the argument from the stack.&nbsp; Then the instructions in red make room on the stack to store the original and modified versions of the control word, then set the control word to round to nearest, and at the end, restore the previous value of the control word.&nbsp; Obviously the &quot;frndint&quot; instruction is what performs the rounding.&nbsp; <br><br>So in all, what could have simply been two instructions (load from memory, store to memory) was turned into 24 instructions.<br><br>With <tt>-ffast-math</tt>, this improves somewhat, and becomes this:<br><br><div class="block"><pre><font color="red">  08049466  D97DFE            fnstcw [ebp-0x2]</font><br>  08049469  DD4508            fld qword [ebp+0x8]<br><font color="red">  0804946c  0FB745FE          movzx eax,word [ebp-0x2]<br>  08049470  B404              mov ah,0x4<br>  08049472  668945FC          mov [ebp-0x4],ax<br>  08049476  D96DFC            fldcw [ebp-0x4]</font><br>  08049479  DB5DF8            fistp dword [ebp-0x8]<br><font color="blue">  0804947c  D96DFE            fldcw [ebp-0x2]</font></pre></div><br>Here, the instructions in red store the floating point control word, then set it to round towards negative.&nbsp; The  instructions in black load the value into the FPU, then perform the floor() by storing it back to memory as an integer.&nbsp; Then the instruction in blue restores the previous value of the control word.<br><br>While 8 instructions is still too many, it's certainly better than four.<br><br>Curious what exactly the default settings for rounding were, I tried using round() instead of floor(), but found that it again reverted to calling a function rather than doing the round() in-line.<br><br>So instead I looked again at the dump of libm, where I found the round() function, which contains the following code:<br><br><div class="block"><pre>  0000ab80  55                push ebp<br>  0000ab81  89E5              mov ebp,esp<br>  0000ab83  83EC18            sub esp,byte +0x18<br>  0000ab86  DD4508            fld qword [ebp+0x8]<br>  0000ab89  DD55E8            fst qword [ebp-0x18]<br>  0000ab8c  8B55EC            mov edx,[ebp-0x14]<br>  0000ab8f  895DF4            mov [ebp-0xc],ebx<br>  0000ab92  E8D089FFFF        call dword 0x3567 __cxa_finalize@plt+0xd3<br>  0000ab97  81C35DA40100      add ebx,0x1a45d<br>  0000ab9d  8975F8            mov [ebp-0x8],esi<br>  0000aba0  8B75E8            mov esi,[ebp-0x18]<br>  0000aba3  89D1              mov ecx,edx<br>  0000aba5  C1F914            sar ecx,0x14<br>  0000aba8  81E1FF070000      and ecx,0x7ff<br>  0000abae  8D8101FCFFFF      lea eax,[ecx-0x3ff]<br>  0000abb4  83F813            cmp eax,byte +0x13<br>  0000abb7  897DFC            mov [ebp-0x4],edi<br>  0000abba  7F54              jg 0xac10 round+0x90<br>  0000abbc  85C0              test eax,eax<br>  0000abbe  0F88AC000000      js dword 0xac70 round+0xf0<br>  0000abc4  BFFFFF0F00        mov edi,0xfffff<br>  0000abc9  89C1              mov ecx,eax<br>  0000abcb  D3FF              sar edi,cl<br>  0000abcd  85D7              test edi,edx<br>  0000abcf  0F84CB000000      jz dword 0xaca0 round+0x120<br>  0000abd5  DC834490FFFF      fadd qword [ebx-0x6fbc]<br>  0000abdb  D9EE              fldz<br>  0000abdd  D9C9              fxch st1<br>  0000abdf  DFE9              fucomip st1<br>  0000abe1  DDD8              fstp st0<br>  0000abe3  7612              jna 0xabf7 round+0x77<br>  0000abe5  BE00000800        mov esi,0x80000<br>  0000abea  89C1              mov ecx,eax<br>  0000abec  D3FE              sar esi,cl<br>  0000abee  F7D7              not edi<br>  0000abf0  8D1416            lea edx,[esi+edx]<br>  0000abf3  31F6              xor esi,esi<br>  0000abf5  21FA              and edx,edi<br>  0000abf7  8955EC            mov [ebp-0x14],edx<br>  0000abfa  8975E8            mov [ebp-0x18],esi<br>  0000abfd  DD45E8            fld qword [ebp-0x18]<br>  0000ac00  8B5DF4            mov ebx,[ebp-0xc]<br>  0000ac03  8B75F8            mov esi,[ebp-0x8]<br>  0000ac06  8B7DFC            mov edi,[ebp-0x4]<br>  0000ac09  89EC              mov esp,ebp<br>  0000ac0b  5D                pop ebp<br>  0000ac0c  C3                ret<br>  0000ac0d  8D7600            lea esi,[esi+0x0]<br>  0000ac10  83F833            cmp eax,byte +0x33<br>  0000ac13  7E13              jng 0xac28 round+0xa8<br>  0000ac15  3D00040000        cmp eax,0x400<br>  0000ac1a  75E4              jnz 0xac00 round+0x80<br>  0000ac1c  D8C0              fadd st0<br>  0000ac1e  6690              xchg ax,ax<br>  0000ac20  EBDE              jmp short 0xac00 round+0x80<br>  0000ac22  8DB600000000      lea esi,[esi+0x0]<br>  0000ac28  81E913040000      sub ecx,0x413<br>  0000ac2e  BFFFFFFFFF        mov edi,0xffffffff<br>  0000ac33  D3EF              shr edi,cl<br>  0000ac35  85F7              test edi,esi<br>  0000ac37  74C7              jz 0xac00 round+0x80<br>  0000ac39  DC834490FFFF      fadd qword [ebx-0x6fbc]<br>  0000ac3f  D9EE              fldz<br>  0000ac41  D9C9              fxch st1<br>  0000ac43  DFE9              fucomip st1<br>  0000ac45  DDD8              fstp st0<br>  0000ac47  7615              jna 0xac5e round+0xde<br>  0000ac49  B933000000        mov ecx,0x33<br>  0000ac4e  29C1              sub ecx,eax<br>  0000ac50  B801000000        mov eax,0x1<br>  0000ac55  D3E0              shl eax,cl<br>  0000ac57  01C6              add esi,eax<br>  0000ac59  7303              jnc 0xac5e round+0xde<br>  0000ac5b  83C201            add edx,byte +0x1<br>  0000ac5e  F7D7              not edi<br>  0000ac60  21FE              and esi,edi<br>  0000ac62  8955EC            mov [ebp-0x14],edx<br>  0000ac65  8975E8            mov [ebp-0x18],esi<br>  0000ac68  DD45E8            fld qword [ebp-0x18]<br>  0000ac6b  EB93              jmp short 0xac00 round+0x80<br>  0000ac6d  8D7600            lea esi,[esi+0x0]<br>  0000ac70  DC834490FFFF      fadd qword [ebx-0x6fbc]<br>  0000ac76  D9EE              fldz<br>  0000ac78  D9C9              fxch st1<br>  0000ac7a  DFE9              fucomip st1<br>  0000ac7c  DDD8              fstp st0<br>  0000ac7e  0F8673FFFFFF      jna dword 0xabf7 round+0x77<br>  0000ac84  81E200000080      and edx,0x80000000<br>  0000ac8a  31F6              xor esi,esi<br>  0000ac8c  83F8FF            cmp eax,byte -0x1<br>  0000ac8f  0F8562FFFFFF      jnz dword 0xabf7 round+0x77<br>  0000ac95  81CA0000F03F      or edx,0x3ff00000<br>  0000ac9b  E957FFFFFF        jmp dword 0xabf7 round+0x77<br>  0000aca0  85F6              test esi,esi<br>  0000aca2  0F852DFFFFFF      jnz dword 0xabd5 round+0x55<br>  0000aca8  E953FFFFFF        jmp dword 0xac00 round+0x80</pre></div><br>Fuck!  Is that what it's doing every time I call round()?<br><br>Assuming they were trying to get a rounding style that the FPU doesn't support, I looked to the man page, where I found this:<br><br><div class="block">These  functions  round x to the nearest integer, but round halfway cases away from<br>       zero (regardless of the current rounding direction, see fenv(3)), instead of to the<br>       nearest even integer like rint(3).</div><br>...and sure enough, looking at the dump of rint(), I finally see some reasonable code:<br><br><div class="block"><pre>  00009230  DD442404          fld qword [esp+0x4]<br>  00009234  D9FC              frndint<br>  00009236  C3                ret<br></pre></div><br>So then I change my code to use rint(), and finally get the output I was looking for:<br><br><div class="block"><pre>  08049467  DD4508            fld qword [ebp+0x8]<br>  0804946a  DB5DF4            fistp dword [ebp-0xc]</pre></div><br>So I tried my test function again from the other day:<br><br><div class="block"><pre>void whatever(double *x, double *y, double a) {<br>  double t;<br>  t = *x * cos(a) - *y * sin(a);<br>  *y = *x * sin(a) + *y * cos(a);<br>  *x = t;<br>};</pre></div><br>With <tt>-ffast-math</tt>, the output is this:<br><br><div class="block"><pre><font color="red">  08049480  55                push ebp<br>  08049481  89E5              mov ebp,esp<br>  08049483  DD4510            fld qword [ebp+0x10]</font><br><font color="orange">  08049486  D9FB              fsincos</font><br><font color="green">  08049488  8B4508            mov eax,[ebp+0x8]<br>  0804948b  8B550C            mov edx,[ebp+0xc]</font><br><font color="blue">  0804948e  DD00              fld qword [eax]<br>  08049490  DD02              fld qword [edx]</font><br>  08049492  D9C2              fld st2<br>  08049494  D8C9              fmul st1<br>  08049496  D9C4              fld st4<br>  08049498  D8CB              fmul st3<br>  0804949a  DEC1              faddp st1<br>  0804949c  DD1A              fstp qword [edx]<br>  0804949e  D9CA              fxch st2<br>  080494a0  DEC9              fmulp st1<br>  080494a2  D9C9              fxch st1<br>  080494a4  DECA              fmulp st2<br>  080494a6  DEE1              fsubrp st1<br>  080494a8  DD18              fstp qword [eax]<br><font color="purple">  080494aa  5D                pop ebp<br>  080494ab  C3                ret</font></pre></div><br>The three instructions in red set up the stack, then load the first parameter, and wouldn't be there if this weren't a function, so they don't matter.&nbsp; (If this code were in-line with other code, the values would likely already be in the FPU stack.)  The instruction in orange is the fsincos that I wanted it to in-line.&nbsp; The instructions in green retrieve the pointers from the stack, again they don't matter since they wouldn't be there if this wasn't a function.&nbsp; The instructions in blue load the values from the pointer, and again, wouldn't be there if this wasn't a function.&nbsp; (In other words, this is a great example of why you want to in-line simple functions, and GCC will do so automatically as long as they are contained within the same source file, as it needs to see the code for them.)  Finally, the instructions in black solve the equations, storing the results back to the original pointers.&nbsp; The instructions in purple restore the stack and return.<br><br>There's really nothing to complain about with the above code.&nbsp; It's as good as anything I might write myself.<br><br>At this point, my complaints rest entirely with GCC's need to set the control word all the time.&nbsp; To solve this problem, I looked for more compiler options, but found none.&nbsp; So then I looked for some functions and found fesetround(), but it appeared that GCC ignores the current rounding mode when compiling code, which makes sense since it usually won't know what it is since it it may have been changed in another function.&nbsp; Thus setting the rounding mode is irrelevant without a function that rounds according to the current rounding mode.&nbsp; So I went looking for one, and found nearbyint() which does just that.&nbsp; By using nearbyint(), the code output by GCC when implicitly converting a double to an int (like with &quot;int x = (double) y&quot;) is simply the instruction to store the value to an integer.&nbsp; <br><br>So in summary, if you want decent math output from GCC, it seems that the following rules apply:<br><br><div class="block"><div class="margin"><br>1.&nbsp; Compile with the <b><tt>-ffast-math</tt></b> option.&nbsp; Ignore the documentation's mention of &quot;unsafe&quot; optimizations.&nbsp; All it means is that it will perform math the way the FPU performs math, rather than exactly the way some random standard you don't care about says that the math must be performed.&nbsp; It's all a bunch of shit about the exact result you get when you perform calculations involving infinity or not-a-number, or in other words, nothing you care about.<br><br>2.&nbsp; Avoid using <tt>floor()</tt>, <tt>ceil()</tt>, and especially <tt>round()</tt>.&nbsp; Instead use <b><tt>fesetround()</tt></b> to set your preferred rounding mode, then use <tt><b>nearbyint()</b></tt> for rounding.&nbsp; Also use <tt>nearbyint()</tt> when storing floating-point results to integer variables rather than using the implicit conversion, as the implicit conversion is slower and likely isn't how you want to round anyway.&nbsp; <br><br>3.&nbsp; Don't forget <tt>-O3</tt>.&nbsp; Always use <tt>-O3</tt>.</div></div><br>Applying those rules to the first code example in <a href="http://www.ecstaticlyrics.com/pinnwand/messages/i_recind_my_previous_statement.html">this post</a> (it was already compiled with -O3, so I only had to apply the first two rules) reduces it's execution time from 16.0 ms to 6.4 ms, which beats the 6.6 ms time of my assembly code.&nbsp; <br><br>So, awesome!  I don't have to write any assembly code now!<br><br>Now if only there were an option to make the modulus functions work correctly.<br><br>Here's a graph of how modulus is supposed to work:  <a href="http://www.wolframalpha.com/input/?i=x+mod+1+for+-3+%3C+x+%3C+%2B3">Wolfram|Alpha graph of x mod 1 for -3 &lt; x &lt; +3</a><br><br>In C, the left half of the graph is shifted downward so that it is below the x axis, and so that there is a continuous line from (-1, -1) to (+1, +1).&nbsp; In other words, the waveform repeats with a period equal to the divisor, except around zero where the period size is double.&nbsp; ...and that's rather undesired behavior when I need a modulus value, since I'm usually trying to divide a continuous range of values into discrete values, each of which represents an equal-size piece of the input range.&nbsp; <br><br>The integer modulus operator (the % symbol) has the same issue, but since I haven't yet needed to use it with potentially negative values, I haven't written a clever macro to perform it correctly.<br><br>The CPU and FPU lack instructions that produce these results.&nbsp; Each does have a way of calculating remainders, but that isn't exactly the same thing, so it's no surprise that the results for negative inputs aren't correct.&nbsp; So using a macro to get the correct result is as good as a dedicated function would be.<br><br>Presently I use this macro to replace fmod() with some simple math that calculates the correct result:<br><br><tt>#define fmod(x, y) ((x) - (y) * floor((double) (x) / (y)))</tt><br><br>I suppose I need to change that to nearbyint() now.<br><br>I have no such macro for integer math since I haven't yet written any code where it would matter, as I've always used % with values that are never negative.&nbsp; ...and I can't think of any way to do it that isn't just nasty.&nbsp; I tried looking for some assembly code, but couldn't find anything that wasn't just a forum post by someone who didn't know that the divide instruction exists.&nbsp; So the best I have to offer is this:<br><br>#define imod(x, y) (0 &lt;= x ? x % y : (x + 1) % y + y - 1)<br><br>It isn't too bad I guess...<br><br><div class="block"><pre>  0804ab5c  85D2              test edx,edx<br>  0804ab5e  7820              js 0x804ab80<br><font color="red">  0804ab60  89D0              mov eax,edx<br>  0804ab62  C1FA1F            sar edx,0x1f<br>  0804ab65  F7F9              idiv ecx</font><br>                              [some code removed]<br><font color="blue">  0804ab80  83C201            add edx,byte +0x1<br>  0804ab83  89D0              mov eax,edx<br>  0804ab85  C1FA1F            sar edx,0x1f<br>  0804ab88  F7F9              idiv ecx<br>  0804ab8a  8D5411FF          lea edx,[ecx+edx-0x1]</font><br>                              [jump to removed code]</pre></div><br>Normally the &quot;[some code removed]&quot; would be a jump to the &quot;[jump to removed code]&quot; but GCC decided to do it the other way for some reason.&nbsp; So it appears that the % just gives us the remainder of IDIV, using three instructions, and that the case for negative numerators requires five instructions.&nbsp; Plus it adds 2 to 3 instructions of overhead depending on which path it follows.&nbsp; However, IDIV isn't exactly a fast instruction anyway.&nbsp; <br><br>The real problem here is that, with constant divisors, GCC will do some neat tricks to perform the calculation faster than IDIV.&nbsp; However, since it has defined the behavior for negative inputs the way it has, you don't get automatic clever tricks that work correctly. <br><br>For example, if you want to do &quot;x % 16&quot; you can instead do &quot;x & 15&quot; and you get the correct result even for negative numbers.&nbsp; However, for &quot;x % 16&quot; GCC generates six instructions, presumably to preserve the incorrect behavior for negative numerators.&nbsp; So you get better code than IDIV, but worse code than a simple AND instruction.&nbsp; There may just as well be similar tricks for correct results with constant denominators like 10, but GCC won't generate those, instead it will generate other code that produces the wrong results.<br><br>...but at this point I'm almost complaining that GCC won't optimize my code for me.&nbsp; So it doesn't matter.&nbsp; I just wanted it to stop de-optimizing it, and the three steps listed above seem to do that just fine.&nbsp; If I ever need the integer modulus fixed, I'm sure I can use an inline assembly function provided I can find a way to calculate it that doesn't suck.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#197</guid>
      <title><![CDATA[Caffeine]]></title>
      <author>Pj</author>
      <pubDate>Tue, 3 Jan 2012 18:26:10 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/caffeine.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">It does seem to be the caffeine.&nbsp; <br><br>Strange thing is that, even if I have just 200 mg in the morning (like 3 cans of soda), it still affects my sleep that night, and seems to have a tiny effect even the night after that.&nbsp; So much for that &quot;avoid caffeine in the evening&quot; advice.&nbsp; Seems you should avoid it entirely.<br><br>Still nothing much seems to be going on with sugar.&nbsp; Eventually I had lost 13 pounds, then Christmas came and suddenly there was a bunch of candy to eat, and so now it's just 10.&nbsp; ...and I'm sorta starting to get tired of those pizzas.&nbsp; Before they were exciting and tasty.&nbsp; Now they're just food.&nbsp; Another month and I may not like them anymore.<br><br>Some day a few days ago I decided I needed some extra stimulation in order to try to wake up.&nbsp; So I went for a walk in the sun, and found it satisfying enough that I decided to buy some new lights for my room.&nbsp; I now have 3000 lux by my estimation.&nbsp; It's more light than the outside on some particularly bad days, like the very next day after I bought the lights, and the day after that.&nbsp; Stupid weather.&nbsp; Hopefully the new lights will help to keep me a little more awake during the day.&nbsp; If nothing else, I do like how much brighter it is now.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#195</guid>
      <title><![CDATA[Sugar, again. ...and pizza. Pizza is awesome!]]></title>
      <author>Pj</author>
      <pubDate>Tue, 13 Dec 2011 01:57:44 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/sugar_again_and_pizza_pizza_is_awesome.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Tired of reading about my sleep?  <b>Skip to the end to find an awesome pizza recipe!</b><br><br>Last month I was experimenting with trying to sleep while sitting up.&nbsp; It seemed to help my sleep, in as much as I could sleep while sitting up, which wasn't much.&nbsp; I tried for a month, but apparently it's too unnatural to get used to.<br><br>Towards the end of the month I was trying more random things.&nbsp; Eventually I thought I noticed something.&nbsp; First I guessed it was the Phenylephrine I'd started taking, but a few nights of experimentation seemed to prove that theory wrong.&nbsp; Then I thought maybe it was the accidental overdose of Galantamine I'd taken, but further nights of the same failed to produce the same result.&nbsp; Indeed, my sleep seemed worse than ever.&nbsp; Then I had an idea...<br><br>When my sleep had become worse than ever was the same time I decided to buy a bunch of glazed doughnuts and chocolate milk and eat nothing but that for a few days.&nbsp; Which reminded me of that whole fructose theory.<br><br>It seemed like such a good one at the time.&nbsp; First of all, when I started avoiding fructose, it seemed to spawn the best week of programming I'd ever had.&nbsp; I've had periods where I've done a lot of programming before, but that week I was just really into it.&nbsp; I added a lot of new code to the game and rewrote some of what was already in it and it's all really cool.&nbsp; So to have that correlate with my avoidance of fructose scores it some points.<br><br>Second, from what I could remember of past periods of improvement, they all correlated with periods when I wasn't eating anything with sugar in it.&nbsp; For example, any time I was riding my bicycle regularly, I wasn't eating anything with sugar in it.&nbsp; The one exception I can think of is the time I decided to go riding in the middle of the night, and was having all sorts of fun until I got to Hueston Woods and then decided to fill up on the PowerAde and granola bars I'd brought with me, after which the rest of the trip was quite terrible.&nbsp; Also, last year when I was writing my Minecraft server, I clearly remember eating nothing besides salads from the Red Front and whey protein shakes, which surprisingly contain little sugar.&nbsp; Even when I first went riding in Hueston Woods many years ago, I remember at the same time being surprised that the Freschetta pizzas I was eating at the time were only about 2,000 calories per day.&nbsp; Can't say that I've checked how much sugar they contain (and I'm talking about seven years ago, so who knows if the recipe has changed anyway), but I doubt they contain much if any since it's a pizza.&nbsp; <br><br><br>The third thing in favor of the fructose theory is that <a href="https://www.youtube.com/watch?v=dBnniua6-oM">the idea just seems credible</a> as far as the bullshit detection circuitry in my brain is concerned.&nbsp; All except for the part where he says fruit is OK, at least.&nbsp; That part just feels wrong, but then since fruit is worshiped in the world of food as being the most healthy thing a person can eat, I wonder if he didn't just think that going against fruit would cause too many people to reject what he says, and that the damage done by fruit is small enough to justify ignoring it in order to get more people to listen to the issues with sugar in general.<br><br>All that said, despite avoiding fructose at all costs, my awesome week of programming failed to turn into an awesome month of programming, <br><br>Anyway, considering all of that, and that the last few days of eating nothing but glazed doughnuts and chocolate milk had correlated with some of the worst sleep I'd had lately, it seemed like it was time to try again.<br><br>So for the last 12 days or so I've been eating nothing but pizzas I've made myself at home, which contain no sugar of any kind, and I've been drinking only water.<br><br>According to data from my Zeo, my sleep has improved, just not a whole lot.&nbsp; Usually I track the minutes of REM sleep per 24 hours divided by the number of awakenings from REM sleep.&nbsp; The average is 9.8 for the last 12 days, compared to 7.something (if only I'd written it down) for the month before that.&nbsp; I also tried a different metric, total REM sleep minus one minute for each awakening from REM sleep.&nbsp; For that I got 3.9 hours for the last 12 days, compared to 2.8 hours for the month before that, which doesn't seem like much but it is a 40% increase in REM sleep.&nbsp; I also calculated the average for the first month I had the Zeo, which was 3.1 hours.&nbsp; <br><br>So according to the Zeo at least, it seems that lack of sugar might be helpful for sleep.&nbsp; Either that or it's the lack of caffeine that came with it.&nbsp; One day I took a caffeine pill in the early afternoon and found that I stayed up much later and had terrible sleep.&nbsp; So I haven't taken any caffeine since then, but I continue to have random periods of poor sleep.&nbsp; I was hoping I wouldn't have any for a week, at which point I could simply try caffeine some days and sugar other days and see which really has an effect, but instead the improvement is subtle enough that I'm not sure anyone would see it other than me, which is why I calculated those averages rather than just posing a picture of my new awesome sleep patterns.&nbsp; <br><br>For some time I've considered asking myself how I feel to be too unreliable, and instead I gauge my wellness by what I do during the day.&nbsp; It's too easy to just think that I feel better, but it's harder to start being more active than I usually would be.&nbsp; I don't seem to be doing much that I wasn't already doing before, and so the score there is quite low, but it does show some improvement.<br><br>The only large improvement I've seen is that I've lost 7 pounds in the last 12 days.&nbsp; That's a nice rate, but weight loss rates don't really count until you're up to a month or so.&nbsp; Until then it's too likely you're looking at a momentary glitch. My appetite also seems to be going down, as initially I was eating three pizzas a day, but now I seem to be down to just two.&nbsp; According to some estimates I made a month ago, each pizza contains about 700 calories, but I also tend to snack on the pepperoni while I make the pizza and so there's probably another 100 or 200 calories in there.<br><br>So, I don't know what's going on at this point, but those pizzas I've been making are quite tasty, so I plan to continue to eat them and see what happens.&nbsp; <br><br>Anyway, over months of making pizza dough, I've learned that there are a lot of recipes.&nbsp; Some people include things like olive oil, sugar, milk, and various other things in their recipes, but I've found that adding anything at all only seems to make the dough worse.&nbsp; If you're going to make pizza dough, use this simple recipe:<br><br>240 grams of water<br>1/2 tsp. of yeast<br>400 grams of flour<br><br>Sprinkle the yeast onto the water, so that it floats on the surface.&nbsp; After a few minutes, it will soak into the water.&nbsp; (otherwise it ends up being a huge glob that's wet on the outside and dry on the inside)  Then stir it to mix it in the water.&nbsp; Then add the flour, and mix for 9 minutes in <a href="http://www.walmart.com/ip/Kitchenaid-4.5-Mixer-White/3215">an electric mixer</a> which, despite the huge price tag, probably pays for itself soon enough considering the $2.50 per meal cost of the pizzas.&nbsp; ...or at least for me considering that nearly every frozen food from Wal-Mart has pissed me off in one way or another and so I'd taken to ordering pizza for $10 a day, plus usually eating something else too.&nbsp; It's important to mix for nine minutes because, while the dough looks like it's mixed before that, the additional mixing time is what makes it nice and bread-like, such that you some day in the future order a pizza and find yourself wondering why the fuck you paid $10 for such low-quality pizza dough.&nbsp; Anyway, after it's all mixed up, divide it into three portions for three 8-9 inch pizzas, or leave as one portion for a 14-16 inch pizza.&nbsp; It'll probably be around 645 grams, so make each portion about 215 grams.&nbsp; I place each portion in a one liter plastic container with a lid.&nbsp; In the lids I poke a small hole with a needle, small enough to keep out gnats, but large enough to allow gases to escape, otherwise the lid will soon pop off.&nbsp; The dough ball is initially quite small, but left at room temperature will eventually grow to nearly fill the container, then shrink to about 1/2 the volume.&nbsp; If then placed in the fridge, it will shrink to about 1/3 to 1/4 the volume.&nbsp; This process doesn't require exact timing.&nbsp; Usually I just leave the things sit for about 12 to 36 hours, then put them in the fridge, since if left out for too many days they don't seem so good anymore.&nbsp; It's normal for the dough to smell like beer.&nbsp; Indeed, it will have alcohol in it, but most of it probably evaporates in the oven.<br><br>When ready to use a dough, first sprinkle some cornmeal onto a table.&nbsp; You can use flour, but cornmeal is much easier to sprinkle.&nbsp; Remove the dough from the container and drop it on the cornmeal, then move it around to make sure all sticky surfaces are coated.&nbsp; Use a rolling pin to turn it into something roughly 8 to 9 inches round, or 14 to 16 inches if you didn't divide your dough into three portions.&nbsp; Then use non-stick spray on a pizza pan, and place the dough on the pan.&nbsp; <br><br>For sauce I mix a can of generic tomato sauce with a can of generic tomato paste, which despite papa john's commercials which imply that tomato paste is some cheap-ass ingredient used as filler, is actually the more expensive ingredient.&nbsp; It thickens up the sauce so that it stays where you put it.<br><br>Then I just top it with the cheapest cheese and pepperoni I can find, and usually I'll add some onion and jalapeno.&nbsp; Some garlic powder on top, after it comes out of the oven, is good too.&nbsp; Again, ignore the papa john's commercials that claim &quot;better ingredients, better pizza.&quot;  It's all in the dough.&nbsp; Save your money and buy the cheapest ingredients you can find, the only exception being that anything fresh is going to be better than anything canned, although even canned stuff is quite tasty when you're too lazy to deal with fresh ingredients.<br><br>Bake the pizza in the oven, on the pan, at 450 degrees for about 14 minutes.&nbsp; Alternately, if you like some darkness on the bottom of your crust, bake for 6 minutes on the pan, then 6 minutes on the rack.&nbsp; I'll warn you that you'll pay for this as the smoke alarm goes off every time you make a pizza, due to sauce and grease dripping off of the pizza and onto the oven floor, where it is super-heated by the heating element.&nbsp; ...or take the easy way out and nevermind the color of the crust.&nbsp; It's cooked when it's on the pan, that's all that matters.<br><br>These pizzas are quite good.&nbsp; I've eaten them exclusively for the last 12 days, and with other foods for a month or two before that.&nbsp; Still not even remotely tired of them, which is much more than I can say for any frozen pizza I've ever bought.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#185</guid>
      <title><![CDATA[Zeo Frequency Response]]></title>
      <author>Pj</author>
      <pubDate>Sun, 11 Sep 2011 06:56:20 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/zeo_frequency_response.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Previously on Pj's Pinnwand...<br><br><div class="block">In particular, I'd like to build a rig to feed waveforms into the Zeo so that I can test the shape of its frequency filters and figure out its actual voltage scale and maybe do some other testing, but I haven't been able to convince myself to clean my electronics desk, let alone build anything, in like a year.</div><br>Well, after deciding I'd really like to make another EEG, I drank some 32 ounces of coffee, and about 90 minutes later, I was cleaning.&nbsp; Then later I felt quite ill after forgetting to eat in spite of not being hungry, as caffeine suppresses appetite.&nbsp; Still not sure if I'll manage to make another EEG, but that testing I wanted to do with the Zeo, that's really not that hard.&nbsp; <br><br>So now I have this:<br><br><center><img src="stuff/zfr.png"></center><br>Horizontal axis is frequency, in Hz.&nbsp; Vertical axis is in µV, showing the response recorded by the Zeo when I input a 100 µV sine wave of that frequency into the headband pod.<br><br>I used this circuit for the interface:<br><center><img src="stuff/zps.png"></center><br>Can't say I know it's correct, but I messed with it for quite a while and this is the best I came up with.&nbsp; The order in which I used the pins is the order in which they lie across the forehead when the electronics pod is attached to the headband.&nbsp; I attached the wires by disassembling an old headband and removing the connectors from it, then attaching wires to those, so that the wires would snap to the electronics pod and stay in place.<br><br>The DC filter really is quite nasty.&nbsp; Here's what it looks like when I feed a 0.5 Hz 100 µV square wave into it:  (The vertical axis has divisions at each 100 µV.)<br><br><center><img src="stuff/half-hertz-square.png"></center><br>I believe the smooth round hump, by crossing over the center line, indicates that there are actually two high-pass filters on the input.&nbsp; With just a single filter, it would instead be a smooth decay back to center.&nbsp; I used to see the same thing happen with my own EEG, as the DC filter on the input, and a second DC filter between two amplifier stages, would do that to each other.&nbsp; Also, I think that the way that the initial spike surpasses 100 µV indicates an excessive high-frequency response, however, I didn't find one while creating the graph at the beginning, and what I've seen of the Fourier transformation at the bottom of the images doesn't indicate one either.&nbsp; So I don't know what's causing that.<br><br>Here is a 1 Hz 100 µV sine wave:<br><br><center><img src="stuff/one-hertz-sine.png"></center><br>It's at 38% amplitude, which is more filtering than I'd like to see, but at least the frequencies are still there, I guess.&nbsp; <br><br>As for those suspected K-complexes, I think the 0.5 Hz square wave image shows that their waveform really could be much different from what was recorded.&nbsp; However, considering the amplitude, event duration, and regularity of occurrence, a K-complex seems to be the best fit.&nbsp; It just isn't a good fit.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#201</guid>
      <title><![CDATA[I recind my previous statement.]]></title>
      <author>Pj</author>
      <pubDate>Thu, 5 Apr 2012 10:57:54 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/i_recind_my_previous_statement.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Today I'm working on some code for my Minecraft server.&nbsp; (Why I'm doing that rather than writing a server for my own game is a very good question.)  Since Minecraft refuses to process block changes faster than a certain rate, I have to send them no faster than that rate in order to avoid lag as Minecraft buffers the block changes and everything that is received after them.&nbsp; So I store a copy of the map for each player (a nice waste of 36 MB per user) and periodically send the differences between that map and the real map to the user.&nbsp; Note that I'm not simply buffering the block changes locally because I want to always be sending the player the changes which are closest to the player's position, and the player can move a lot in the several minutes of backed-up data that can occur when large portions of the map are changed.<br><br>This introduces a new problem:  How to compare the player's map to the real map in a time frame that makes sense for something that is done 10 times a second for up to 36 players.&nbsp; Given that the map is 36 MB in size, simply comparing each block isn't feasible.<br><br>So instead I've divided the map into 8x8x64 chunks, each of which has a flag (per user) which is set by the function that changes map blocks.&nbsp; Then I simply scan those flags, and find the closest chunk with a flag set, and send blocks from that chunk.&nbsp; This is repeated a few times if necessary to come up with the 100 blocks I'm allowed to send each player every 0.1 seconds.&nbsp; <br><br>I'd like to reduce this to 1x1x64 chunks, one chunk for each (x, y) position on the map, as it seems a bit more responsive to player movement and looks better.&nbsp; However, as the map is 768x768x64, the (x, y) array contains 589824 bytes whose flags need to be checked, and, if the flag is set, then the distance to that chunk calculated.&nbsp; Then, because the chunk size is so small, it's far more likely that I'll need to repeat this search multiple times to find the next closest chunk.&nbsp; ...and if that wasn't bad enough, everyone demands this &quot;/fly&quot; command on the server which places glass blocks under the player so that he can walk in the air, and implementing it means that the chunks around the player are always marked as needing updating, and so every search first results in the 9 chunks nearest the player before any changes I actually need to send turn up.<br><br>So I've been writing some code to test the feasibility of sorting an array of all of the (x, y) positions by distance from the player.&nbsp; I figure that even if this takes a bit too long on its own, I can simply not do it only once for one player every 0.1 seconds, choosing the player whose distance table is most out of date, and also adding a requirement for how far the player must move before the table is recalculated.<br><br>So, first thing to do is fill in the table with the distances:  <br><br><div class="block"><pre>__attribute__ ((noinline)) static void calculate_distances() {<br>  double px = floor(234.5);<br>  double py = floor(123.4);<br>  double pz = floor(012.3);<br>  int i = 0;<br>  for (int y = 0; y &lt; MAP_Y_SIZE; y++) {<br>    for (int x = 0; x &lt; MAP_X_SIZE; x++) {<br>      double dx = px - x;<br>      double dy = py - y;<br>      int d = sqrt(dx * dx + dy * dy) * 1000;<br>      distance_data[i].x = x;<br>      distance_data[i].y = y;<br>      distance_data[i].d = d;<br>      i++;<br>    };<br>  };<br>};</pre></div><br>This results in the following assembly code:<br><br><div class="block"><pre>08049490 calculate_distances:<br>  08049490  55                push ebp<br>  08049491  89E5              mov ebp,esp<br>  08049493  57                push edi<br>  08049494  31FF              xor edi,edi<br>  08049496  56                push esi<br>  08049497  53                push ebx<br>  08049498  83EC4C            sub esp,byte +0x4c<br>  0804949b  C745DC00000000    mov dword [ebp-0x24],0x0<br>  080494a2  8DB600000000      lea esi,[esi+0x0]<br>  080494a8  897DE4            mov [ebp-0x1c],edi<br>  080494ab  8B75DC            mov esi,[ebp-0x24]<br>  080494ae  31DB              xor ebx,ebx<br>  080494b0  DB45E4            fild dword [ebp-0x1c]<br>  080494b3  DC2DC87A0508      fsubr qword [dword 0x8057ac8]<br>  080494b9  C1E604            shl esi,0x4<br>  080494bc  81C6C4E8FA0A      add esi,0xafae8c4<br>  080494c2  D8C8              fmul st0<br>  080494c4  D905C07A0508      fld dword [dword 0x8057ac0]<br>  080494ca  8DB600000000      lea esi,[esi+0x0]<br>  080494d0  895DE4            mov [ebp-0x1c],ebx<br>  080494d3  DB45E4            fild dword [ebp-0x1c]<br>  080494d6  D8E9              fsubr st1<br>  080494d8  D8C8              fmul st0<br>  080494da  D8C2              fadd st2<br>  080494dc  D9C0              fld st0<br>  080494de  D9FA              fsqrt<br>  080494e0  DBE8              fucomi st0<br>  080494e2  7A06              jpe 0x80494ea calculate_distances+0x5a<br>  080494e4  742A              jz 0x8049510 calculate_distances+0x80<br>  080494e6  DDD8              fstp st0<br>  080494e8  EB06              jmp short 0x80494f0 calculate_distances+0x60<br>  080494ea  DDD8              fstp st0<br>  080494ec  8D742600          lea esi,[esi+0x0]<br>  080494f0  DD1C24            fstp qword [esp]<br>  080494f3  D9C9              fxch st1<br>  080494f5  DD5DC8            fstp qword [ebp-0x38]<br>  080494f8  DD5DB8            fstp qword [ebp-0x48]<br>  080494fb  E8E4F8FFFF        call dword 0x8048de4 sqrt@plt<br>  08049500  DD45B8            fld qword [ebp-0x48]<br>  08049503  DD45C8            fld qword [ebp-0x38]<br>  08049506  D9CA              fxch st2<br>  08049508  EB08              jmp short 0x8049512 calculate_distances+0x82<br>  0804950a  8DB600000000      lea esi,[esi+0x0]<br>  08049510  DDD9              fstp st1<br>  08049512  891E              mov [esi],ebx<br>  08049514  83C301            add ebx,byte +0x1<br>  08049517  897E04            mov [esi+0x4],edi<br>  0804951a  D97DE2            fnstcw [ebp-0x1e]<br>  0804951d  D80DC47A0508      fmul dword [dword 0x8057ac4]<br>  08049523  0FB745E2          movzx eax,word [ebp-0x1e]<br>  08049527  B40C              mov ah,0xc<br>  08049529  668945E0          mov [ebp-0x20],ax<br>  0804952d  D96DE0            fldcw [ebp-0x20]<br>  08049530  DB5EFC            fistp dword [esi-0x4]<br>  08049533  D96DE2            fldcw [ebp-0x1e]<br>  08049536  83C610            add esi,byte +0x10<br>  08049539  81FB00030000      cmp ebx,0x300<br>  0804953f  758F              jnz 0x80494d0 calculate_distances+0x40<br>  08049541  DDD8              fstp st0<br>  08049543  DDD8              fstp st0<br>  08049545  8145DC00030000    add dword [ebp-0x24],0x300<br>  0804954c  83C701            add edi,byte +0x1<br>  0804954f  817DDC00000900    cmp dword [ebp-0x24],0x90000<br>  08049556  0F854CFFFFFF      jnz dword 0x80494a8 calculate_distances+0x18<br>  0804955c  83C44C            add esp,byte +0x4c<br>  0804955f  5B                pop ebx<br>  08049560  5E                pop esi<br>  08049561  5F                pop edi<br>  08049562  5D                pop ebp<br>  08049563  C3                ret<br></pre></div><br>I'll spare everyone my analysis of the code, mostly because I just don't fucking care to analyze it.&nbsp; It's too fucking long, I'll tell you that much.<br><br>Here's the time data from a loop of 100 executions of the code:<br><br><div class="block"><pre><br>Lag percentiles per function:<br>    90%    50%    10%     1%  worst  total<br>   16.0   16.0   16.0   19.9   19.9  21.0%  calculate_distances()</pre></div><br>Units are milliseconds.&nbsp; The 'worst' field is obviously the longest time of all trials.&nbsp; The &quot;90%&quot; field means that 90% of the trials took at least that long.&nbsp; The &quot;10%&quot; field means that 10% of the trials took at least that long.&nbsp; I guess the 50% field is the best to pay attention to.<br><br>Anyway, I decided to rewrite this code in assembly, and came up with this:  (displayed in objdump format, to match the display of GCC's output, as I doubt anyone would try to read the assembly code anyway)<br><br><div class="block"><pre>080493d0 calculate_distances:<br>  080493d0  60                pushad<br>  080493d1  9BD93D60E20508    fstcw [dword 0x805e260]<br>  080493d8  9BDBE3            finit<br>  080493db  D92D307A0508      fldcw [dword 0x8057a30]<br>  080493e1  DB052C7A0508      fild dword [dword 0x8057a2c]<br>  080493e7  DD051C7A0508      fld qword [dword 0x8057a1c]<br>  080493ed  DB1D50E20508      fistp dword [dword 0x805e250]<br>  080493f3  DB0550E20508      fild dword [dword 0x805e250]<br>  080493f9  DD05147A0508      fld qword [dword 0x8057a14]<br>  080493ff  DB1D50E20508      fistp dword [dword 0x805e250]<br>  08049405  DB0550E20508      fild dword [dword 0x805e250]<br>  0804940b  DD050C7A0508      fld qword [dword 0x8057a0c]<br>  08049411  DB1D50E20508      fistp dword [dword 0x805e250]<br>  08049417  DB0550E20508      fild dword [dword 0x805e250]<br>  0804941d  BF00000000        mov edi,0x0<br>  08049422  B900000000        mov ecx,0x0<br><br>08049427 y_loop:<br>  08049427  BB00000000        mov ebx,0x0<br><br>0804942c x_loop:<br>  0804942c  898FC4E8D60A      mov [edi+0xad6e8c4],ecx<br>  08049432  899FC0E8D60A      mov [edi+0xad6e8c0],ebx<br>  08049438  DB87C4E8D60A      fild dword [edi+0xad6e8c4]<br>  0804943e  D8E2              fsub st2<br>  08049440  DCC8              fmul to st0<br>  08049442  DB87C0E8D60A      fild dword [edi+0xad6e8c0]<br>  08049448  D8E2              fsub st2<br>  0804944a  DCC8              fmul to st0<br>  0804944c  DEC1              faddp st1<br>  0804944e  D9FA              fsqrt<br>  08049450  D8CC              fmul st4<br>  08049452  DB9FC8E8D60A      fistp dword [edi+0xad6e8c8]<br>  08049458  81C70C000000      add edi,0xc<br>  0804945e  43                inc ebx<br>  0804945f  81FB00030000      cmp ebx,0x300<br>  08049465  75C5              jnz 0x804942c x_loop<br>  08049467  41                inc ecx<br>  08049468  81F900030000      cmp ecx,0x300<br>  0804946e  75B7              jnz 0x8049427 y_loop<br>  08049470  9BDBE3            finit<br>  08049473  D92D60E20508      fldcw [dword 0x805e260]<br>  08049479  61                popad<br>  0804947a  C3                ret<br></pre></div><br>No real &quot;optimization&quot; since with code this trivial there really isn't anything to optimize as its rather obvious how it should go together.&nbsp; I used ebx and ecx to as the x and y loop iterators, and edi as the 'i' variable, except that I just use it as a pointer to the structure and increment it by 12 each loop.&nbsp; GCC probably made a pointer too, I imagine.&nbsp; Don't care to dig through that code to look for it though.<br><br>Here's the run time data for that code...<br><br><div class="block"><pre>Lag percentiles per function:<br>    90%    50%    10%     1%  worst  total<br>    6.6    6.6    6.6   10.3   10.3   9.9%  calculate_distances()</pre></div><br>Same calculations in only 41% of the time.&nbsp; Nice.<br><br>...and, yes, I compiled with -O3.&nbsp; Like I always tell everyone, compiler optimization doesn't so much improve your code as it merely improves the awful mess the compiler would otherwise output without optimizations enabled.<br><br>I'll now have to try rewriting the sorting algorithm in assembly.&nbsp; I'm interested to see how the improvement in execution speed compares when the code being rewritten is non-trivial.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#207</guid>
      <title><![CDATA[The Fast Fourier Transformation, in understandable terms.]]></title>
      <author>Pj</author>
      <pubDate>Fri, 4 May 2012 04:31:31 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/the_fast_fourier_transformation_in_understandable_terms.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">...or at least I hope I can explain it understandably.&nbsp; I've wanted to know how to do the fast fourier transfor forever, but despite reading many descriptions of it, I always ran in to one problem:  Smart people suck.&nbsp; A lot.<br><br>Some of it has to do with them really not being that smart.&nbsp; There's a set of people who enjoy the idea that they are smart, and so believe that they know things that they don't really understand, and when you search for information about something and find one of their explanations, you end up reading something that makes no sense and often just ignores the more complex aspects, which are obviously the parts you need the most help with.<br><br>The rest of it comes from what I can only assume is some attempt by the smart people to show off their smarts.&nbsp; They'll often explain the simpler parts in excessive detail, but then be as concise as possible with the more complex parts, utilizing every bit of advanced bullshit they know, seemingly just to show off that they know it.&nbsp; <br><br>I suppose I could be wrong, but then where else does shit like this come from?<br><br><center><img src="stuff/incomprehensible.png" class="borderless"><br><small><br>Image from Wikipedia's &quot;Fast Fourier Transform&quot; page.</small></center><br>Ooh, look!  Someone knows maths!<br><br>One sure sign that your description sucks is when someone who already knows how to do what you're describing can't even understand it.&nbsp; I've known how to do slow Fourier transforms for years.&nbsp; I had to figure out on my own how to do them as I never found a decent explanation of how they work.&nbsp; Even after I knew how to do them, I still saw equations like the above and could think nothing other than &quot;what the fuck?&quot;  It wasn't until Wolfram Alpha explained what the &quot;e ^ (-i * 2 * pi)&quot; meant that I had any idea how the above formula had anything at all to do with what I already knew how to do.&nbsp; It's a neat mathematical trick I suppose, and certainly useful when creating a concise statement of the algorithm, but when you're trying to explain something to someone who doesn't already know it, concise isn't what you want.&nbsp; <br><br>So, having finally figured out how the fast Fourier transform works, (and, again, with no help from the smart people of the world, but rather, I just sat down and figured it out on my own), I feel the need to explain in simple understandable terms how it works.&nbsp; <br><br>Hopefully I've accomplished that as I've now spent enough hours writing this that I'm no longer sure I care.<br><br><h3>Step 1:  The slow Fourier transform.</h3><br>Since the fast Fourier transform is an optimization of the slow Fourier transform, I should first explain how that works.<br><br>I first discovered how to do this while reading an electronics textbook about radio communications.&nbsp; I was reading about how to &quot;mix&quot; the antenna signal with a frequency in order to shift the radio frequencies down to audio frequencies.&nbsp; ...but nevermind all that.<br><br>The important thing I learned from this book is that if you have two sine waves of frequencies A and B, and you multiply the waveforms together, the resulting waveform is the sum of the frequencies A+B and A-B.&nbsp; <br><br>At first I found this difficult to believe, and so I wrote some QuickBASIC programs to verify it.&nbsp; However, in the age of Wolfram Alpha, verifying such things is as simple as clicking a link:  <a href="http://www.wolframalpha.com/input/?i=2+*+cos%28a*x%29+*+cos%28b*x%29+%3D+cos%28%28a+%2B+b%29+*+x%29+%2B+cos%28%28a+-+b%29+*+x%29">2 * cos(a*x) * cos(b*x) = cos((a + b) * x) + cos((a - b) * x)</a>  Still, a result of &quot;true&quot; doesn't do justice to just how amazing it is.<br><br>In writing those QuickBASIC programs, I quickly realized that I could use this property of sine waves to figure out how much of a frequency was in an input signal.&nbsp; By multiplying the input waveform by the frequency I wanted to look for, that frequency would be shifted to 0 Hz, turning it into a DC offset.&nbsp; I could then average the signal over the sample period, and that average would represent to what degree that frequency was present.<br><br>The only problem was that the resulting DC offset depended on the phase difference between the frequency as it existed in the input signal, and the frequency I was multiplying.&nbsp; If they were both the same phase, the DC offset was at its maximum, but if they were 90 degrees out of phase, the DC offset was zero.&nbsp; To solve this, I simply performed the operation twice, once using sin() and another using cos(), and thus one of those was guaranteed to produce a non-zero average.&nbsp; I then found that treating the two resulting values as an (x, y) coordinate, and finding the distance from origin (which is sqrt(x*x+y*y) if you didn't already know), gave a result that was constant regardless of the phase of the input signal.&nbsp; Also, the angle of (x, y) represented the phase of the frequency in the input.<br><br>To sum all of that up in some C code:<br><br><div class="block"><pre>  float x = 0;<br>  float y = 0;<br>  for (int i = 0; i &lt; SAMPLE_COUNT; i++) {<br>    x += sample[i] * cos(2 * M_PI * frequency * i / SAMPLE_RATE);<br>    y += sample[i] * sin(2 * M_PI * frequency * i / SAMPLE_RATE);<br>  };<br>  x /= 0.5 * SAMPLE_COUNT;<br>  y /= 0.5 * SAMPLE_COUNT;<br>  float magnitude = sqrt(x * x + y * y);<br>  float angle = atan2(y, x);</pre></div><br>You'll likely want to do it multiple times for several frequencies, but that's the basic idea.<br><br>There is a lot more to it, however.&nbsp; For example, it's mathematically the case that the only frequencies it makes sense to look for are those given by this code:<br><br><div class="block"><pre>  for (float f = 0.0; f &lt;= SAMPLE_RATE / 2; f += SAMPLE_RATE / SAMPLE_COUNT) {</pre></div><br>Frequencies above SAMPLE_RATE / 2 simply aren't present in the data, and while you can test for more than the steps of SAMPLE_RATE / SAMPLE_COUNT, the resulting data isn't any more accurate.&nbsp; Basically it's a matter that there's only so much input data and so you're only going to get so much output data.<br><br><h3>Step 2: The Fast Fourier Transform</h3><br>The key to understanding the fast Fourier transform came to me when, while reading a PDF about it written by some moron, it occurred to me that it couldn't be anything other than just an optimization of the above.&nbsp; So at that point I decided &quot;fuck everyone else and their incomprehensible explanations&quot; and instead focused on figuring out how to do it on my own.&nbsp; I should have done that years ago as it only took a day of thinking about the problem to figure it out.<br><br>The first obvious optimization is to realize that only certain sine/cosine values are used.&nbsp; You can create an array of just the values for the lowest frequency, then step through that array twice as a fast for the next frequency, then 3 times as fast for the third frequency, etc.&nbsp; However, that doesn't address the O(n^2) complexity of the problem, and thus has nothing to do with fast Fourier transforms.&nbsp; <br><br>So I wrote out the steps for a small transform of eight data points, figuring that if I could find an optimization there, then I could extrapolate that to larger data sets.<br><br>A transform of eight data points (assume eight samples of data at eight samples/second) involves summing each of the eight samples multiplied by the cos/sin values for that frequency.&nbsp; Here are the operations in table form:<br><br><center><table border="2" cellpadding="4" cellspacing="2"><tr><th>Frequency</th><th>Sample 0</th><th>Sample 1</th><th>Sample 2</th><th>Sample 3</th><th>Sample 4</th><th>Sample 5</th><th>Sample 6</th><th>Sample 7</th></tr><tr><th>cos 0</th><td align="center">1</td><td align="center">1</td><td align="center">1</td><td align="center">1</td><td align="center">1</td><td align="center">1</td><td align="center">1</td><td align="center">1</td></tr><tr><th>sin 0</th><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td></tr><tr><th>cos 1</th><td align="center">1</td><td align="center">0.7071</td><td align="center">0</td><td align="center">-0.7071</td><td align="center">-1</td><td align="center">-0.7071</td><td align="center">0</td><td align="center">0.7071</td></tr><tr><th>sin 1</th><td align="center">0</td><td align="center">0.7071</td><td align="center">1</td><td align="center">0.7071</td><td align="center">0</td><td align="center">-0.7071</td><td align="center">-1</td><td align="center">-0.7071</td></tr><tr><th>cos 2</th><td align="center">1</td><td align="center">0</td><td align="center">-1</td><td align="center">0</td><td align="center">1</td><td align="center">0</td><td align="center">-1</td><td align="center">0</td></tr><tr><th>sin 2</th><td align="center">0</td><td align="center">1</td><td align="center">0</td><td align="center">-1</td><td align="center">0</td><td align="center">1</td><td align="center">0</td><td align="center">-1</td></tr><tr><th>cos 3</th><td align="center">1</td><td align="center">-0.7071</td><td align="center">0</td><td align="center">0.7071</td><td align="center">-1</td><td align="center">0.7071</td><td align="center">0</td><td align="center">-0.7071</td></tr><tr><th>sin 3</th><td align="center">0</td><td align="center">0.7071</td><td align="center">-1</td><td align="center">0.7071</td><td align="center">0</td><td align="center">-0.7071</td><td align="center">1</td><td align="center">-0.7071</td></tr><tr><th>cos 4</th><td align="center">1</td><td align="center">-1</td><td align="center">1</td><td align="center">-1</td><td align="center">1</td><td align="center">-1</td><td align="center">1</td><td align="center">-1</td></tr><tr><th>sin 4</th><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td></tr></table></center><br>For the frequency zero (the DC offset) you just sum all eight samples (and divide by eight afterwards).&nbsp; This is because the cosine of zero is one, and the sine is zero, thus the coefficients are always one and zero.<br><br>For frequency one, the values are more complex, but the calculation is the same: multiply each sample by the coefficient, then sum the results, and divide by eight.&nbsp; Then you have two sums, one for cos and one for sin, which like above create a vector whose magnitude represents the amplitude and angle represents the phase of the frequency.<br><br>The first obvious thing that stands out is all of the coefficients which are just zeros and ones.&nbsp; However, accounting for them isn't a useful optimization because there is only so many of them because of the small sample size.&nbsp; Larger sample sizes contain far fewer of them.&nbsp; Smaller sample sizes contain nothing but ones and zeros.<br><br>So I stared at this for some hours until I started to wonder what exactly I was getting by including the odd-numbered samples when calculating the value for frequency one.&nbsp; I can calculate a value for that frequency using only the odd samples or only the even samples.&nbsp; So why not just leave out the odd samples and save myself the trouble?  What was I getting by including them in the calculation that I wouldn't get without including them.<br><br>Then I realized that what including the odd samples gets me is the ability to distinguish frequency 1 from frequency 3.&nbsp; Without them, if I have frequency 3 in the sample, it triggers a result for frequency 1.&nbsp; <br><br>Then it occurred to me that by calculating the transforms for the even and odd samples separately, I could combine the two results like this:<br><br><div class="block">cos 0 = even 0 + odd 0<br>cos 1 = even 1 + odd 1<br>cos 2 was completely different<br>cos 3 = even 1 - odd 1<br>cos 4 = even 2 - odd 2</div><br>The sin sums could be calculated similarly, except for the sin sum for frequency 3.&nbsp; The odd sum was there unmodified, but the even sum was different.<br><br>Then it occurred to me that the values for cos 3 weren't simply copied from the values for cos 1, but rather, the values were the result of a rotation of that vector, and it just happened that the rotations were such that the values were quite similar.&nbsp; <br><br>The value for sample 0 was copied unmodified.<br>The value for sample 1 was rotated 90 degrees, which results in the negative value for the cos sum, but results in the same value for the sin sum.<br>The value for sample 2 was rotated 180 degrees, which results in the same value for the cos sum, but the negative value for the sin sum.&nbsp; <br>The value for sample 3 was rotated 270 degrees, which results in the negative value for the cos sum, but results in the same value for the sin sum.<br>Samples 4 through 7 follow the same pattern.<br><br>At this point, I realized it would probably do me a lot of good to look at the problem in terms of complex numbers, and so I scrapped the page and started a new one.<br><br>If you don't know what complex numbers are, here's a quick tutorial:<br><br>Basically, each complex number is composed of two normal numbers.&nbsp; One, the &quot;real&quot; component, is like any other number.&nbsp; The other component, called the &quot;imaginary&quot; part, is defined by the special constant &quot;i&quot; which has the unique property that multiplying it by itself results in the value of -1.&nbsp; Now, if you know how to multiply, you know that there are no numbers that when multiplied by themselves result in a negative number, but that's why it's called &quot;imaginary.&quot;  These numbers are usually expressed in the form of &quot;a + bi&quot; where &quot;a&quot; is the real part and &quot;b&quot; is the imaginary part.&nbsp; An alternative syntax is to represent them as an (x, y) coordinate, with x being the real component and y being the imaginary component.<br><br>Adding two such numbers, such as &quot;a + bi&quot; and &quot;c + di&quot; simply results in &quot;(a+b) + (c+d)i&quot;, or in other words, you just add together the two real parts, then separately add together the two imaginary parts.&nbsp; The resulting vector is the point you get when you take the segment from (0, 0) to (a, b) and stick it on the end of (c, d).&nbsp; If (a, b) is (1, 0) and (c, d) is (0, 1) then the new vector is (1, 1).<br><br>Multiplying two such numbers is particularly interesting.&nbsp; To multiply them, you simply use &quot;distribution&quot; which you learned in algebra class.&nbsp; (a + bi) * (c + di) = (a * b) + (a * di) + (c * bi) + (bi * di), and since i multiplied by itself turns into -1, the (bi * di) at the end turns into simply -(b * d).&nbsp; Thus the real component is (a * c) - (b * d), and the imaginary component is (a * d) + (b * c).<br><br>Why complex numbers are useful in this case is that the provide a simple way to rotate vectors.&nbsp; To rotate a vector by an angle, all you have to do is express it as a complex number, then multiply it by a vector of length one at the angle you want to rotate the first vector by.<br><br>For a simple example, consider if you have (1, 0) and you want to rotate it 90 degrees.&nbsp; To calculate the unit length vector for 90 degrees, just calculate (cos(90), sin(90)), which happens to be (0, 1) which makes this an easy example.&nbsp; When you multiply (1, 0) by (0, 1) the result is (0, 1).&nbsp; Then you multiply again, and now the result is (-1, 0).&nbsp; Then you multiply again, and now the result is (0, -1).&nbsp; Finally, if you multiply again, you're back to (1, 0), as four times 90 degrees is a full circle.&nbsp; <br><br>This works no matter what angle you use.&nbsp; For a more complex example, consider 45 degrees, whose unit length vector is (0.7071, 0.7071).&nbsp; (which is (cos(45), sin(45)).&nbsp; If you multiply that by itself (thus rotating a 45 degree vector by 45 degrees) you get this result:<br><br>real = 0.7071 * 0.7071 - 0.7071 * 0.7071 = 0<br>imaginary = 0.7071 * 0.7071 + 0.7071 * 0.7071 = 1<br><br>Which is (0, 1) which is the 90 degree angle.<br><br>So, let's rewrite the table from above, but now we'll assume that we are dealing with complex numbers.&nbsp; Obviously our eight samples won't have imaginary parts, but now rather than calculate two sums, we calculate just one which contains both the cosine and sine sums as real and imaginary parts.&nbsp; Also, rather than put the complex number representing each angle in each box, I'll just put a single digit, which is the index into the array of cosine/sine values (which I'll explain a bit more below).&nbsp; <br><br><center><table border="2" cellpadding="4" cellspacing="2"><tr><th>Frequency</th><th>Sample 0</th><th>Sample 1</th><th>Sample 2</th><th>Sample 3</th><th>Sample 4</th><th>Sample 5</th><th>Sample 6</th><th>Sample 7</th></tr><tr><th>0</th><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td></tr><tr><th>1</th><td align="center">0</td><td align="center">1</td><td align="center">2</td><td align="center">3</td><td align="center">4</td><td align="center">5</td><td align="center">6</td><td align="center">7</td></tr><tr><th>2</th><td align="center">0</td><td align="center">2</td><td align="center">4</td><td align="center">6</td><td align="center">0</td><td align="center">2</td><td align="center">4</td><td align="center">6</td></tr><tr><th>3</th><td align="center">0</td><td align="center">3</td><td align="center">6</td><td align="center">1</td><td align="center">4</td><td align="center">7</td><td align="center">2</td><td align="center">5</td></tr><tr><th>4</th><td align="center">0</td><td align="center">4</td><td align="center">0</td><td align="center">4</td><td align="center">0</td><td align="center">4</td><td align="center">0</td><td align="center">4</td></tr></table></center><br><br>Since all of our frequencies are a multiple of frequency 1, we only need a table of the values for frequency 1, of which there are eight, one for each sample.&nbsp; Then for frequency 2, we just step through the array twice as fast, and once we reach the end, we wrap to the beginning again.&nbsp; For frequency 3, we step by threes.&nbsp; Thus there are only eight values we ever multiply any of the samples by.<br><br>So, again, let's look at how we might combine the results of two separate transforms, one of the even samples and a another of the odd samples.&nbsp; To make that comparison simpler, I'll make two separate tables for those two transforms:<br><br><center><table><tr><th>Transform A</th><th>Transform B</th></tr><tr><td><center><table border="2" cellpadding="4" cellspacing="2"><tr><th>Frequency</th><th>Sample 0</th><th>Sample 2</th><th>Sample 4</th><th>Sample 6</th></tr><tr><th>0</th><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td></tr><tr><th>1</th><td align="center">0</td><td align="center">2</td><td align="center">4</td><td align="center">6</td></tr><tr><th>2</th><td align="center">0</td><td align="center">4</td><td align="center">0</td><td align="center">4</td></tr><tr><th>3</th><td align="center">0</td><td align="center">6</td><td align="center">4</td><td align="center">2</td></tr></table></center></td><td><center><table border="2" cellpadding="4" cellspacing="2"><tr><th>Frequency</th><th>Sample 1</th><th>Sample 3</th><th>Sample 5</th><th>Sample 7</th></tr><tr><th>0</th><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td></tr><tr><th>1</th><td align="center">0</td><td align="center">2</td><td align="center">4</td><td align="center">6</td></tr><tr><th>2</th><td align="center">0</td><td align="center">4</td><td align="center">0</td><td align="center">4</td></tr><tr><th>3</th><td align="center">0</td><td align="center">6</td><td align="center">4</td><td align="center">2</td></tr></table></center></td></tr></table></center><br><br>Obviously the result for frequency zero is just the sum of the result for 0 from each of the two separate transforms.&nbsp; The results for the other three can be calculated like so:<br><br>Frequency 1:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 1.<br><br>Frequency 2:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 2.<br><br>Frequency 3:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 3.<br><br>At this point we haven't really saved any time.&nbsp; We're doing just as many calculations, just in a different order.&nbsp; Where we save time comes from re-using the above values to calculate the next four frequencies.<br><br>Frequency 4: take the result from transform A, and add to it the result from transform B, advanced in phase by angle 4.<br><br>Frequency 5:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 5.<br><br>Frequency 6:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 6.<br><br>Frequency 7:  take the result from transform A, and add to it the result from transform B, advanced in phase by angle 7.<br><br>If you draw out a similar reduction of the two tables above into four smaller transforms, a pattern becomes apparent:<br><br>1.&nbsp; The values in the combined transform always come from the values in the smaller transform in the same pattern:  The first frequency's value always comes from the first values in the two smaller transforms.&nbsp; The second result always comes from the second values.&nbsp; Also, like above, the second (new) set of frequencies in the result is always re-uses the first set of values in the same way.<br><br>2.&nbsp; The angle by which the second set needs to be advanced is equal to the difference in angle between the two sets multiplied by the frequency.&nbsp; Thus, above, it was always just the frequency itself.&nbsp; In the second recursion, however, the difference in angle between the two transforms is twice as large, thus then phase adjustment is twice as large.<br><br>Thus, the idea is simple and the patterns are simple, and so there's no reason why people need to make it seem so difficult.&nbsp; Even the math is simple enough if you take the time to explain it.<br><br><h3>Step 3: Implementation</h3><br>I wrote <a href="/code/download/fft.c">some code</a> to implement this algorithm.&nbsp; It isn't very self-explanatory, so I'll explain how I implemented it here.<br><br>First thing to notice is that C99 includes a complex data type.&nbsp; Type &quot;man complex&quot; in Linux to learn about it.&nbsp; Thus, rather than manage cosine/sine or real/imaginary values manually, I just used the standard data type.<br><br>The first thing to do is to calculate the cosine/sine values and store them into a table.&nbsp; To do that, I use code like this:<br><br><div class="block"><pre>  for (int i = 0; i &lt; samples; i++) {<br>    table[i] = cexp(-2 * M_PI * I * i / samples);<br>  };</pre></div><br>This is similar to the &quot;e ^ (-2 * pi * i * n / N)&quot; in the formula above that I copied from Wikipedia.&nbsp; Turns out this nonsense is a simple way to get the cosine/sine pair as a complex number.&nbsp; The &quot;k&quot; term is left out, since we include it when we index into this array.&nbsp; <br><br>To implement the transform, I decided to write a function which takes five arguments.&nbsp; Two are pointers to an input/output array, &quot;temp&quot; and &quot;data&quot; below, but exactly which is the input and which is the output is complicated.&nbsp; The third argument is an index into the sample data.&nbsp; The fourth is a step size.&nbsp; The fifth is the number of samples to be transformed.&nbsp; <br><br><div class="block"><pre>  if (count &gt; 2) {<br>    recursive(temp, offset, step &lt;&lt; 1, count &gt;&gt; 1, data);<br>    recursive(temp, offset + step, step &lt;&lt; 1, count &gt;&gt; 1, data);<br>  };</pre></div><br>To split the transform into two smaller transforms is rather simple.&nbsp; The first has the same offset, but the step size is doubled, while the count is halved.&nbsp; The second is similar, except that the offset is incremented by the step size.&nbsp; This recursion is continued until there are only two samples to be transformed.&nbsp; The transformation of a single sample is just that sample itself.&nbsp; Thus there's no reason to call the functions in that case since they would simply return their original value.<br><br>Then to combine the two transforms, I use this code:<br><br><div class="block"><pre>  for (int i = 0; i &lt; count &gt;&gt; 1; i++) {<br>    int a = offset + step * i;<br>    int b = offset + step * (2 * i);<br>    int c = offset + step * (2 * i + 1);<br>    int d = (step * i) & (samples - 1);<br>    data[a] = temp[b] + temp[c] * table[d];<br>  };<br>  for (int i = 0; i &lt; count &gt;&gt; 1; i++) {<br>    int a = offset + step * (i + (count &gt;&gt; 1));<br>    int b = offset + step * (2 * i);<br>    int c = offset + step * (2 * i + 1);<br>    int d = (step * (i + (count &gt;&gt; 1))) & (samples - 1);<br>    data[a] = temp[b] + temp[c] * table[d];<br>  };</pre></div><br>The two for() loops handle the first and second halves of the frequency range.&nbsp; <br><br>Variable &quot;a&quot; calculates the index into the array we store our results into.&nbsp; Thus it is the offset we were given, incremented by the step size for each subsequent result.&nbsp; the second for() loop's equation adds half of the count to this, since it's doing the second half of the frequencies.<br><br>Variables &quot;b&quot; and &quot;c&quot; calculate the index into the results from the first and second transforms, which is why the &quot;i&quot; is multiplied by two (each transform processed every other value) and &quot;c&quot; is offset by 1.&nbsp; <br><br>Variable &quot;d&quot; calculates the offset into the table of cosine/sine values in complex number format.&nbsp; Again, &quot;count &gt;&gt; 1&quot; is added in the second for() loop in order to cover the higher range.&nbsp; The result is then clipped so that it doesn't overflow the array, so that the index values just wrap around the array as necessary.<br><br>Finally, since C99 has that complex data type, the actual math is rather simple.&nbsp; <br><br>data[a] = temp[b] + temp[c] * table[d];<br><br>All of the values are complex numbers, thus what the C compiler generates is actually four multiplies and four additions.&nbsp; <br><br>There are obviously many ways this could be optimized.&nbsp; I haven't bothered since, short of keeping the cosine/sine values in a table, nothing makes as much of a difference as simply using a fast transform vs. a slow one.&nbsp; <br><br>However, were I to decide I needed to, the most obvious approach I can think of is to add &quot;printf()&quot; statements that output the operations as a long list of C code, then simply let GCC optimize it.&nbsp; With all of the values printed out, GCC would easily see where all of those multiplies by zero or one are and optimize them away and it would certainly figure out how best to use the FPU stack to avoid unnecessarily storing values to memory.&nbsp; If I included the code that converts my data into complex numbers, it would likely even find optimizations that result from the excess of zero imaginary parts in the input data.<br><br>As for which of the &quot;data&quot; and &quot;temp&quot; are input and output, there's a fun story behind that...<br><br>It started with me trying to optimize a merge sort I'd written.&nbsp; The merge sort works in a similar way, dividing its input into two halves, then calling itself to sort each half, then simply merging the two sorted halves, which is an easier problem to solve.<br><br>At first it would take the input data, pass it to itself to sort the two halves, then copy that data to a temporary workspace so that it could overwrite the original data when sorting the data out of the temporary space.&nbsp; Thus there was a full copy of the data for each recursion, and it occurred to me that eliminating that would save some time.<br><br>So I thought that if I just changed the function so that, rather than sorting the data in place, it sorted it into a new buffer, the problem would be solved.&nbsp; So I changed the function's arguments to require separate input and output buffers.<br><br>This created a problem, however, due to the fact that the function calls itself.&nbsp; I now had to change those calls to also use separate input and output buffers.&nbsp; So those calls now moved the data from the input buffer to the output buffer, which again meant that I had to move it back to the input buffer before I could merge the lists into the output buffer.&nbsp; <br><br>Unfortunately I didn't figure that out so easily.&nbsp; I must have rewritten the function ten times, confusing the hell out of myself since it seemed obvious there must be some way to do this without needlessly copying the data for each recursion, but when I changed the function to require separate input/output buffers, it needed to call the function it was before when it sorted into the same buffer, but when I changed it back to that, it now needed a function that used separate input/output buffers.<br><br>So I solved this problem with copy & paste.&nbsp; I made two copies of the function, one which takes the data in one buffer and returns it in the other, and the other which takes the data in the output buffer, sorts it, and simply uses the input buffer as scratch space.&nbsp; Each function called the other recursively.&nbsp; Finally it did what it was supposed to.<br><br>This was the code which I decided to rewrite in assembly to see if I could beat the compiler's code.&nbsp; <br><br>So after writing one version of the code in assembly, I decided to diff the two functions to see what exactly I had to change.&nbsp; Turns out the two functions contained only one difference:  The function that sorts in place would return immediately when asked to sort one item, whereas the function that used separate input/output buffers first copied that single item to the output buffer, then returned.&nbsp; Other than that, the two functions were identical.<br><br>This prompted me to test the hell out of the two functions to verify they did what I thought they did.&nbsp; ...and indeed they did.&nbsp; Calling &quot;sort_yes_move&quot; would sort the data in its second argument and return it in its first, and calling &quot;sort_no_move&quot; would sort the data in its first argument and return it in the same place.&nbsp; ...and yet the two functions differed only via that one line of code.<br><br>I must have thought about this in the back of my mind for a day before I finally figured out why it worked.<br><br>Basically, since each recursion of the function moves the data from one buffer to the other, which buffer it needs to be in to begin with depends on whether the recursion depth is odd or even.&nbsp; Since the functions call each other, that tracks the odd/even depth, and the statement to copy the data from the one buffer to the other in the one function takes care of copying it before anything is done.&nbsp; The functions also inverted the order of their two arguments when calling each other, so that each one read the data written into the opposite buffer by the other.&nbsp; Thus, which function I called first determined which buffer was considered input and which was considered output and also determined whether it was an even or odd recursion depth that required the data to be moved first.<br><br>In my FFT code, I encountered the same problem:  When merging the two sets of data, I needed to preserve the results from the recursive calls while calculating the results of the current step.&nbsp; So I did the same thing, making the recursive calls reverse the order of the two buffers.&nbsp; However, rather than use two copies of the function, I instead just used one, and took care of copying the data to the correct buffer before calling the recursive function:<br><br><div class="block"><pre>    if ((int) trunc(log(samples) / log(2) + 0.5) & 1) {<br>      memmove(temp, input, samples * sizeof(complex));<br>    } else {<br>      memmove(data, input, samples * sizeof(complex));<br>    };</pre></div><br>The formula there just figures out whether the number of samples is an even or odd power of two, which determines whether there will be an even or odd number of recursive steps, and thus, which of the two buffers will be the first one to be read from.&nbsp; It then copies the data into that buffer.&nbsp; (An alternate method would be to always copy the data to the same buffer, but to call the recursive function with the &quot;data&quot; and &quot;temp&quot; parameters in a different order for each of the two cases, and then copy the data from the correct pointer afterwards.)  (...or, as another alternative, you could just copy it to both arrays...)<br><br>So, in the event anyone reads all of that and now understands the Fast Fourier Transform despite not previously understanding it, please let me know that I've accomplished my goal and I'll turn this into something more permanent than a blog post.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#176</guid>
      <title><![CDATA[The Anti-Viral License]]></title>
      <author>Pj</author>
      <pubDate>Wed, 20 Jul 2011 07:28:21 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/the_anti_viral_license.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I've never been a fan of the GPL, but while working on this game, I've really come to hate it.&nbsp; For example, I was working on some code to allow people to choose passwords, and I thought it might be nice to include cracklib in order to tell people whether or not they are choosing a good password.&nbsp; While investigating the license, I learned that it was originally GPL, but then converted to LGPL because the authors wanted it to be as widely used as possible.&nbsp; However, LGPL isn't the best way to do that.&nbsp; There's some myth that the LGPL is like the BSD license in that it lets people include your library in their program without infecting their program with your library's license.&nbsp; It's only true under some very specific circumstances, which aren't circumstances I cared to utilize.&nbsp; So I tried to make my own, realized it sucked, then gave up.<br><br>Unfortunately, I don't think most people who choose the GPL really understand what it means.&nbsp; It's just &quot;the free software license&quot; and they like free software, so they choose the free software license.&nbsp; Saves them the trouble of having to hire a lawyer to write all that &quot;INCLUDING THE IMPLIED WARRANTIES OF&quot; nonsense, which everyone assumes they need or else they'll be sued into bankruptcy.<br><br>Other people use the BSD license, but then some GPL fool comes along and incorporates their code into their program, placing it under the GPL license.&nbsp; Then any changes made to the previously BSD licensed code are then only available under a GPL license.&nbsp; Thus the thing spreads like a virus, even though some people refuse to see it that way.<br><br>Some day I'll want to release my game as open source, but I won't want it to be GPL.&nbsp; Why should it be when I haven't been able to use any GPL code while writing it?  ...and I won't want it to be BSD either because what good is a license that allows my code to become GPL when I don't want it to be GPL?  ...and at the same time, I don't want to make my code incompatible with other free software licenses, since the idea is for the code to be available for other people to use, and incompatible licenses don't help that goal.&nbsp; <br><br>Introducing:  <a href="http://www.ecstaticlyrics.com/secret/The Anti-Viral License">The Anti-Viral License</a><br><br>It's a license whose only requirement is that the code not be relicensed under some other license.&nbsp; So, if you create a derivative work, that derivative work must be licensed under the anti-viral license, but it specifically allows using the work as part of a greater work without the requirement that the other components of the greater work assume the same license.&nbsp; So some of the source for a program can be Anti-Viral, and some can be BSD, and some can be public domain, but none of it can be GPL because the GPL requires that the entire project become GPL.&nbsp; Thus, the license is anti-viral, in that it protects the code from the GPL license, and also protects entire projects in which the code is used from being relicensed under the GPL, and it does all of this while remaining compatible with any non-viral license that exists presently or in the future.&nbsp; <br><br>Indeed, the anti-viral license itself isn't incompatible with the GPL, but rather, the GPL is incompatible with the anti-viral license.&nbsp; If a future version of the GPL drops its viral components, it becomes compatible with the anti-viral license automatically.<br><br>I also left out the typical nonsense disclaimers which usually appear in software licenses.&nbsp; It's all just outdated shit from the era when you would buy software that came with licenses that said &quot;you have not bought this computer program, but rather, you have bought only the media on which it is contained&quot; thus claiming that you were bound by the license agreement even if you don't copy the program or make a derivative work because the software was &quot;licensed&quot; to you rather than &quot;sold&quot; to you.&nbsp; Although court rulings have cleared up the nonsense, it still remains in software licenses today because software licenses are mostly copy and paste work of previous licenses, since people largely have no idea what they are doing when they write them.&nbsp; Indeed, nothing requires you to accept a software license to use software, and even click-through license agreements fail based on the legal requirement that contracts cannot be unilateral and you already had the right to use the software before clicking the button, but nonsense licenses continue to exist.&nbsp; Ever wonder why there's so much uppercase text in them?  It's because certain contract terms aren't enforcible unless they appear in bold type, but back in 1980, bold type wasn't all that easy, particularly in plain text files.&nbsp; Copy and paste for 31 years and you have difficult-to-read uppercase text on web pages and in print, where bold text is quite simple, but seemingly no one remembers why the text is uppercase at all, so they don't make it bold.<br><br>There's no need for any of it.&nbsp; If someone is going to sue you, seeing &quot;you can't sue me&quot; in your license isn't going to convince them not to.&nbsp; ...and do you really think a court will hold you responsible for some buggy code you wrote, or might they find that responsibility lies with the person who found something on the internet for free and expected it to work flawlessly?  Sure, courts can make stupid decisions, but just as your license won't keep you from being sued, it won't eliminate stupidity either.&nbsp; Also, you might be hit by a bus tomorrow.&nbsp; Shit happens.<br><br>So the license just explains what it is and why it is what it is, and leaves it at that, leaving it short enough for anyone who even mildly cares to have time to read it.<br><br>I also left out BSD-style clauses about attribution of code sources.&nbsp; I don't see any reason to burden people with such nonsense in the modern age.&nbsp; You can take any library and with a simple internet search figure out who its authors are, and the kind of people who are interested in things like taking someone else's work and slapping their name on it unmodified aren't going to be dissuaded by the license anyway.&nbsp; In the end, it seems like an effect of people not wanting to give away something for nothing, and wishing to at least become famous if not rich.&nbsp; ...but it doesn't matter:  If a lot of people use your code, you'll be famous.<br><br>Basically, this license is about the removal of stupid distinctions.&nbsp; If your code calls my code, why does whether it's part of the same program or a separate program determine whether it is a derivative work?  If I write a function and give it to you, why does using that function in your program make your program a derivative work, while compiling it as a separate program and then using fork() and exec() to call it not make it a derivative work?  There's no reason to think that it matters other than to have an excuse to spread like a virus.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#206</guid>
      <title><![CDATA[...and, having built the other 7 channels now...]]></title>
      <author>Pj</author>
      <pubDate>Sat, 28 Apr 2012 14:42:14 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/and_having_built_the_other_7_channels_now.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Here's a screen capture:<br><br><center><a href="stuff/fuck.png"><img src="stuff/fuck_small.png"></a></center><br>I really need to make a pause button to stop the motion when making screen captures so it doesn't have those weird discontinuities in the image.<br><br>The third and fourth channel show some alpha waves (they're the things that look more like sine waves and less like noise) which appear when the eyes are closed.&nbsp; The first channel is mostly flat because I used it as input to the DRL electrode.&nbsp; Haven't figured out how to make it work on averaged electrodes, which is strange because I thought that would be simple.<br><br>Still no idea what's going on with my heart rate.&nbsp; Tried to stay away from the caffeine, but nothing gets done without it.<br><br>I noticed the same thing last time I did this (which was years and years ago).&nbsp; I mentioned it to my doctor years ago, who seemed concerned and ordered an ECG, but it didn't show anything.&nbsp; ...but then, they only run the test for about 2 seconds, just enough to record a couple of beats.&nbsp; <br><br>I suppose the thing to do might be to write some code now to dump it to a PDF file, print it out, and show him that.<br><br>I'd include a photo of the EEG circuit itself, but I'm so tired I can barely type.&nbsp; ...or maybe it's because it's too cold in here since I haven't turned on the heat.&nbsp; Either way, it's time to go to sleep anyway,<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#190</guid>
      <title><![CDATA[A reply, perhaps.]]></title>
      <author>Pj</author>
      <pubDate>Sat, 24 Sep 2011 08:29:09 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/a_reply_perhaps.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">It's hard to say if this is in response to the email.&nbsp; I received it on paper through normal mail.&nbsp; <br><br>If it is a response to my email, it'd been nice if it included some information to the effect of &quot;your conclusions about your sleep disorder are wrong and here's why&quot; if not a &quot;you're right, we're wrong.&quot;  ...but, I believe I hope for too much.&nbsp; There's no way they're going to acknowledge anything I wrote about.&nbsp; The only response Dr. Reddy was able to make to what I had to say during the office visit was &quot;but this report indicates an AHI of 2.3 and anything less than 5 is non-clinical.&quot;  I am <i>really</i> starting to believe that sleep doctors don't know how to read the data themselves, but instead just feed it into a computer program and rely on the output of the computer.<br><br><div class="block">Dear Mr. Cooper,<br><br>Dr. Reddy would like for you to work with me on a program for your sleep.&nbsp; It is not a mental health program.&nbsp; It is a process with a goal that we will work toward together to improve your sleep.&nbsp; It is called cognitive therapy.&nbsp; <br><br>The cost of the program is $120.00.&nbsp; This includes 5 meetings with the nurse, a book and other materials that are used to complete the program.<br><br>Enclosed you will find information on cognitive therapy for Insomnia, a booklet that talks about good sleep habits, and a sleep diary.&nbsp; If you are interested in the program, please contact me at the number listed on the enclosed business card.<br><br>Also, if you would keep the sleep diary for two weeks as I need the information from your sleep diary to help with setting initial goals with you.<br><br>I hope you will call me.&nbsp; I have helped other people improve their sleep.&nbsp; If you have any questions don't hesitate to call me.&nbsp; I am here to assist you in anyway I can.<br><br>Sincerely,<br>Joyce E. Gray BSN, RN</div><br>The &quot;this is not a mental health program&quot; was included because I asked about that before I left the sleep center.&nbsp; &quot;Cognitive therapy&quot; sure sounds a lot like &quot;cognitive behavioral therapy.&quot;  <br><br>...and, from what I can tell, it isn't much different.&nbsp; Neither seems to be well defined, and consists mainly of talking to people to &quot;figure out&quot; what's wrong, then setting goals to fix those problems, then claiming any success to be a result of the therapy while claiming any setbacks to be unrelated to the therapy.&nbsp; In other words, it's a prime candidate for a placebo effect.&nbsp; Therapy continues until the problem is solved, or in other words, until the patient would have improved on their own anyway, but since they were receiving therapy at the time, we'll claim the therapy was the cause of the improvement.<br><br>Some excerpts from the pamphlet titled &quot;Cognitive Behavioral Therapy for INSOMNIA&quot; (look at that, apparently it is &quot;cognitive behavioral therapy&quot;):<br><br><div class="block"><b>Is the the SAME Old &quot;Do's and Don'ts&quot; of Good Sleep Practices that I Have Read?</b><br><br>No.&nbsp; While those &quot;Do's and Don'ts&quot; may be a starting point, the most effective forms of Cognitive-Behavioral Therapy for Insomnia go far beyond those simple suggestions.<br><br><b>HOW are these Factors Addressed by CBT for Insomnia?</b><br><br>CBT is based on two premises.&nbsp; First, that some (though not all) of the personal and physiologic factors can be directly altered.&nbsp; Second, that the maladaptive thoughts (cognitions) and behaviors (habits) are learned and that they serve to perpetuate insomnia.&nbsp; If they are learned, then they can be &quot;unlearned&quot; by the CBT process.</div><br>Sounds like a mental health program to me.&nbsp; Quite similar to the &quot;you're not depressed for any legitimate reason, but rather, you just think about things the wrong way&quot; hypothesis of depression.<br><br>Also included was a &quot;sleep hygiene&quot; pamphlet which includes all of the information anyone with five minutes on the internet can find, and thus, nothing that anyone with a sleep disorder hasn't already tried.&nbsp; ...and much of it shows all the signs of being meme-quality material, stuff which has no scientific basis, but just sounds reasonable and so anyone who hears it is happy to repeat it.&nbsp; Did you know that if you go swimming after eating that you can get stomach cramps and drown?  The world is full of shit which everyone &quot;knows&quot; yet it isn't the least bit true.&nbsp; <br><br>My favorites are the things that directly contradict each other.&nbsp; For example, to signal the brain to wake up in the morning, supposedly even bright indoor lighting is insufficient, and bright sunlight is required.&nbsp; Yet, at night, apparently even dim indoor lighting can keep the mind from recognizing the approaching evening.&nbsp; Another example is the suggestion that you go to bed only when you are sleepy, since lying in bed awake will &quot;train the mind that lying in bed isn't a signal to go to sleep,&quot; yet at the same time, you're supposed to go to bed at the same time every night in order to make sure that your mind knows what time it should go to sleep.&nbsp; It's plainly obvious that most of this information exists only because someone thought of it one day and other people agree that it sounds good, and so they repeat it.&nbsp; That's how memes come into existence.<br><br>Finally, a &quot;sleep diary&quot; was included.&nbsp; I absolutely despise these things.&nbsp; They basically have a list of questions that you're supposed to fill in for each day, yet the questions are difficult to answer without interfering with your sleep in order to collect the data.<br><br>&quot;What time did you go to bed&quot; and &quot;what time did you wake up&quot; assume you do these things just once, or at the very least, that one of your sleep periods is significantly longer than the others.&nbsp; <br><br>&quot;How long did it take to fall asleep&quot; can be quite difficult to measure without constantly looking at the clock, however, constantly looking at the clock makes it harder to fall asleep.&nbsp; Not to mention that you have to remember the last time you saw the next morning, thus you can't just glance at the clock, but rather, you really have to take note of what time it is.<br><br>&quot;How many times did you wake up during the night&quot; depends largely on the degree to which you awoke, as that determines whether or not you remember.&nbsp; ...and I've found that just trying to count awakenings causes more of them to happen.&nbsp; In my early sleep experiments I had a button I could push to mark awakenings so that I knew where to look for problems in my sleep recordings, but I quickly noticed that simply intending to push the button made awakenings more severe than they otherwise were.&nbsp; Without the button, I'd wake up, but being nearly asleep, just fall asleep again.&nbsp; With the button, I had to wake up enough to move around, find the button (which, despite being affixed to my bed, still required finding), push it, then return to a comfortable sleeping position.&nbsp; The best thing to do for awakenings is to not even think about them.&nbsp; Just go to sleep.&nbsp; However, trying to count them requires you to think about them, which doesn't help the problem at all.<br><br>&quot;How many hours of sleep did you get&quot; also requires you to stare at the clock, only now, not only do you have to do it when falling asleep, but also each time you awaken during the night, and again in the morning, if you're still tired and think you will fall asleep again, but you need to know when you woke up in case you don't.&nbsp; None of that helps with sleep.<br><br>Finally, &quot;rate your sleep on a scale of 1 to 10&quot; requires some extreme rating skill.&nbsp; I have a difficult time rating such subjective feelings on a scale of 1 to 5 with any repeatable accuracy.&nbsp; My Zeo asks me for a 1 to 5 rating each morning, and after two days I just decided to ignore the damn thing.&nbsp; I've done enough experiments with rating to know that there's no chance that the numbers I enter are going to have any value.&nbsp; &quot;How alert are you&quot; is in a similar position, except that having all day to think about it, it is possible to come up with a reasonable score if you carefully define what sort of attributes each point on the scale should reflect.&nbsp; However, no one is going to do that, and so expecting even 5 point accuracy is expecting a bit much.&nbsp; Without a carefully designed scale, it's far too easy for any placebo effects to squeeze their way in.<br><br>...and at the end of the diary is, of course, a copy of the Epworth Sleepiness Scale.&nbsp; I've written about this scale in great length before.&nbsp; So I'll just add that I can't help but think that what usefulness this scale has may well be limited to people simply deciding on their own what sort of score they think they should have, and adjusting their answers accordingly.&nbsp; It's rather easy to do, and anyone who is sleepy has a high motivation to answer &quot;correctly&quot; in order to make sure that they receive treatment.&nbsp; Someone who is quite sleepy might well put a &quot;3&quot; for &quot;sitting and reading&quot; even though, in reality, they'd stop reading and take a nap rather than fall asleep while reading.&nbsp; The instructions &quot;even if you have not done some of these things recently try to work out how they would have affected you&quot; leave a lot of wiggle-room.&nbsp; Might as well just say &quot;rate your sleepiness on a scale of 1 to 10&quot; and leave it at that.<br><br>I mean, fuck, I can probably design a better scale in five minutes.&nbsp; Let me set the timer and see what I come up with:<br><br><div class="block">Rate your sleepiness on this scale from 1 to 5:<br><br>1.&nbsp; Hey, let's go to the gym and exercise!<br><br>2.&nbsp; I frequently engage in low-energy activities like watching television and browsing the internet rather than doing more enjoyable things like spending time with friends and family and engaging in non-sedimentary hobbies.&nbsp; <br><br>4.&nbsp; I hate that my house is a mess, yet I still don't clean it.<br><br>3.&nbsp; I haven't had a shower in two weeks.<br><br>5.&nbsp; This is too hard.&nbsp; Why do I have to answer this?</div><br>There is no excuse for the Epworth Sleepiness Scale.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#199</guid>
      <title><![CDATA[Awesome Pizza and its Lack of Vitamins]]></title>
      <author>Pj</author>
      <pubDate>Sat, 10 Mar 2012 21:33:46 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/awesome_pizza_and_its_lack_of_vitamins.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Oh look!  It's a picture of my food!<br><br><center><img src="stuff/pizza.jpg"></center><br><br>Despite expectations that I'd grow tired of eating my pizza after a while, that doesn't seem to have happened.<br><br>So after eating little else for the last few months, I decided to figure out the vitamin content of my pizza.&nbsp; To do this, I used &quot;Composition of Foods -- Raw, Processed, Prepared -- USDA National Nutrient Database for Standard Reference, Release 21.&quot;  No idea where I got this data.&nbsp; It's been in a folder on my hard drive for ages, along with some Perl scripts I wrote to search and display the data.<br><br>So what's the vitamin content look like?  Below is the percentage of the daily recommended intake for each vitamin that is contained in two pizzas like the above.&nbsp; I calculated for two pizzas since I eat two a day.&nbsp; The vitamin content for the onion on the pizza is not included since for some reason the database has no data on onions.&nbsp;  <br><tt><br>Vitamin A - 24% <br>Vitamin B1 - 153% <br>Vitamin B2 - 106%<br>Vitamin B3 - 98%<br>Vitamin B5 - 20%<br>Vitamin B6 - 30%<br>Vitamin B9 - 75%<br>Vitamin B12 - 48%<br>Vitamin C - 33%<br>Vitamin D - 1%<br>Vitamin E - 13%<br>Vitamin K - 24%<br>Calcium - 59%<br>Magnesium - 28%<br>Zinc - 40%<br>Iron - 120%<br></tt><br>Wow...&nbsp; Between all the &quot;healthy&quot; junk in there like bread, tomato sauce, cheese, jalapeño peppers, and the onions (for which data isn't included), I was expecting something more complete than that.&nbsp; <br><br>I'm not sure to what extent the pizza really is vitamin deficient.&nbsp; Things like recommended daily intakes are prone to situations where researchers determine an amount, double it for &quot;good measure,&quot; then publish the doubled amounts so that agencies responsible for making recommendations can read those doubled amounts, then double them for &quot;good measure&quot; before making their own recommendations.&nbsp; Thus it's quite possible that 25% of the daily intake is all anyone really needs anyway, and thus the pizza is really only deficient in vitamins D and E.&nbsp; <br><br>While looking up what all of these vitamins are, I found listed in the <a href="https://en.wikipedia.org/wiki/Vitamin_B6#Deficiencies">Vitamin B6 Deficiency</a> symptom list a curious item called <a href="https://en.wikipedia.org/wiki/Somnolence">Somnolence</a> which sounded very familiar.&nbsp; So I checked out the other symptoms, and found <a href="https://en.wikipedia.org/wiki/Seborrhoeic_dermatitis">Seborrhoeic Dermatitis</a> which didn't look familiar until I saw the photo of the shaved head, which reminded me of how my own head appears at times when I shave the portion of it under my hair.&nbsp; I also noticed <a href="https://en.wikipedia.org/wiki/Conjunctivitis">Conjunctivitis</a> which reminded me of the time I was at a doctor appointment and one of the assistants thought I might have pink eye, but my doctor said I was probably just tired.<br><br>I think I have something new to try.&nbsp; Not that I haven't tried vitamins before, but I now have something to try them in combination with.<br><br>Since moving into my own tiny house five weeks ago, I've found it relatively easy to be awake during the day and asleep at night.&nbsp; At first I assumed it was because my bedroom window faces the sunrise, but it likely also has to do with my recent discovery of caffeine's extreme effect on my sleep, and my subsequent avoidance of it.&nbsp; Getting any caffeine during the day seems to not only disturb my REM sleep, but it also causes me to stay up a few hours later before going to sleep.&nbsp; I've found that for optimal sleep (again, according to my Zeo) I need to eat only my pizzas, as other random foods seem to be detrimental, and I also need to consume 1/2 of a Hershey bar of chocolate each morning, since for some reason a very small amount of caffeine seems to be better than no caffeine at all.<br><br>However, despite figuring out how to get the longest segments of uninterrupted REM sleep I've ever seen my Zeo record, I haven't actually felt that much better.&nbsp; So something is still missing, and maybe it's this vitamin thing.&nbsp; It's quite possible that the avoidance of caffeine is simply making me less likely to fully awaken from bad REM sleep, rather than actually improving my breathing during REM sleep.<br><br>These B vitamins, however, seem to be involved in production of a lot of neurotransmitters.&nbsp; B5, which I only get 20% of, is used in the production of acetylcholine, which is used to control muscle movement, and so may be responsible for my airway muscles not keeping my airway open during sleep.&nbsp; B6, which I only get 30% of, is used in the production of the neurotransmitters serotonin, epinephrine, norepinephrine and gamma-aminobutyric acid.&nbsp; ...and everyone knows that B12 is responsible for virtually everything, and I only get 48% of it.<br><br>I guess I will overdose on some vitamins for a while and see if that helps.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#196</guid>
      <title><![CDATA[FailBlog -- seemingly the most intelligent place on the internet]]></title>
      <author>Pj</author>
      <pubDate>Sun, 18 Dec 2011 22:08:48 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/failblog_seemingly_the_most_intelligent_place_on_the_internet.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Whenever I read Slashdot, I often find that I read the comments to the stories simply because I want to confirm that someone, somewhere, sees the obvious bullshit.&nbsp; Usually that's the case, though often it's just one or two comments out of a hundred, but sometimes no one sees the truth, which is quite miserable for a web site whose participants all consider themselves to be of above-average intelligence.<br><br>...but then, I guess I shouldn't expect much of a web site whose visitors pride themselves on being nerds.&nbsp; I know they equate &quot;nerd&quot; with &quot;intelligent person&quot; but ... well, I could write thousands of words about the difference between a nerd and an intelligent person, but that isn't what this post is about.<br><br>Lately I've found FailBlog & friends to be the gathering place of intelligent people on the internet.&nbsp; It's a bit of a surprise since I remember reading the comments on the site a year or two ago and finding it to be complete idiocy, but it's really changed since then.<br><br>It's quite amazing.&nbsp; I can see a picture and think something, then look at the comments and find someone who's said exactly what I was thinking.<br><br>For example, a few weeks ago, in the &quot;art of trolling&quot; section, they had an image of the title page of a copy of the book &quot;Bridge to Terabithia&quot; on which someone had written &quot;the girl dies.&quot;  I'd never read the book, but I watched the movie, which I found a complete disappointment.&nbsp; Trailers for the movie focused on scenes cut entirely from the three minutes of the movie illustrating the fantasy land that this boy and girl imagine, whereas the movie is much more reality-based, and ends with an absolutely pointless death of a main character.<br><br>So I read the comments, and one says something like &quot;the real troll was the trailers for that movie which made it look like a fun fantasy film.&quot;  Fuck yes!  Nothing makes me happier than finding that my opinions aren't unique to me.<br><br>What inspired me to write a post today was a comment about <a href="http://thereifixedit.failblog.org/2011/12/15/white-trash-repairs-diy-roller-trainer/">a do-it-yourself bicycle trainer</a> in which someone wrote:  &quot;When you’re actually riding, you can counter unbalance by steering, moving the bike closer to your centre of gravity.&quot;<br><br>OMG!  I'm no longer the only person who understands what keeps a bicycle balanced!  (from the design of those trainers, which connect a front roller to a back roller so that steering the bike causes it to move side to side, obviously other people knew, but this is the first time I've heard someone correctly explain how it works)<br><br>Seriously, I've heard that gyroscopic effect explanation far too much.&nbsp; Then there's other nonsense about it being because you just lean from side to side as you slowly start to fall over, and the gyroscopic effect makes it work just by making you fall over slower.&nbsp; Then I once read some shit that was totally ridiculous, but supposedly proven by a bicycle someone built that removed what they said allowed it to keep balance, but seemingly for no reason at all, also had a funky steering system that made it so that when you'd turn the bars left, the wheel would steer right, but of course they claimed that didn't matter since you were trying to go straight anyway, and so the fact that you couldn't balance obviously wasn't because of the reversed steering.&nbsp; Interesting that someone would go so far as to build a bicycle that causes you to fall more quickly than if you weren't moving at all by using your subconscious steering efforts against you, yet fail to see what they had done and instead attribute it to something else.<br><br>I don't understand how it's so hard to understand.&nbsp; You can't correct your balance by leaning because if you shift to the left, the rest of the bike shifts to the right.&nbsp; It's like floating in space, trying to move in one direction by shifting your weight.&nbsp; Any mass you move in one direction is countered by mass you had to move in the other direction to make that happen.&nbsp; You can't do it.&nbsp; The only thing you can do is when you start to fall to the left, steer a little to the left to put the bike back under you.&nbsp; It's pretty obvious if you try to ride while holding the bars perfectly still as if they were welded in place.&nbsp; You can't do it without falling over.<br><br>Also, if you pay attention, when you're going into a turn which you need to lean into, in order to lean into it you first have to turn in the opposite direction, so the bike moves out from under your center of mass, so that you begin to fall that way.&nbsp; You can't turn left without first turning a little to the right.&nbsp; Otherwise your body continues in a straight line as the bike turns, and soon you and your bike are in different places.<br><br>It just seems wrong to me that people don't know these things.&nbsp; Even more wrong that people think they know these things because they hear the gyroscopic effect explanation, see the demonstration of a bicycle wheel hanging on a string, then consider that a suitable explanation without considering that the weight of a human is easily going to turn that wheel.&nbsp; Not to mention, if the effect is so strong, how do bicycles do anything other than go in a straight line?  Indeed, if I imagine riding at high speed, with the wheel spinning quickly and thus having as much gyroscopic effect as ever, I still don't want to let go of the bars and trust the wheel to keep itself on any sort of straight path.&nbsp; I'd fully expect it to quite suddenly turn to one side or the other and my face to end up in the pavement.&nbsp; The gyroscopic effect might contribute something, but I don't see how it could be enough that, if it were to suddenly disappear, anyone would notice.<br><br>However, like many things, what seems obvious to me seems unknown to everyone else.&nbsp; Except on FailBlog.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#186</guid>
      <title><![CDATA[The joy of debugging...]]></title>
      <author>Pj</author>
      <pubDate>Mon, 12 Sep 2011 07:39:51 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/the_joy_of_debugging.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Every now and then I come across a bug in some program I'm writing that just doesn't seem to have a logical cause.&nbsp; So I decided to document this one.&nbsp; Then, hating to leave the story incomplete, I figured out the problem, documenting all the steps along the way.&nbsp; It's amazing how a simple mistake can turn into hours of debugging.<br><br>I'm working on a multi-source program, and find that sometimes it doesn't work correctly.&nbsp; After trying to find the problem for a while, I discover something interesting...<br><br>When I edit a certain source file, the program stops working.&nbsp; If I then edit another certain source file, it starts working again.&nbsp; This is true even if the edits are trivial, such as adding or removing a comment.<br><br>So I check the object files.&nbsp; They're identical for both working and non-working versions.&nbsp; So I check the executable...&nbsp; It's different.&nbsp; <br><br>I eventually figure out this is because my build script sorts files according to modification time, so that the most recently modified files are compiled first, so that there's less wait to see errors.&nbsp; So, I modify it so that it still does this, but always puts the object files in the same order when linking.&nbsp; <br><br>I then start fresh looking for the problem.&nbsp; After commenting out various parts of the program, I track down a single line of code which can be removed to fix the problem, which is the one shown here in bold type:<br><br><tt>double new_real = real[f] * cos(angle) - imaginary[f] * sin(angle);<br>double new_imaginary = real[f] * sin(angle) + imaginary[f] * cos(angle);<br>real[f] = new_real; imaginary[f] = new_imaginary; phase[f] = new_phase;<br><b>real[f] = 1.0 / 32.0 * sample + 31.0 / 32.0 * real[f];</b><br>double a = sqrt(real[f] * real[f] + imaginary[f] * imaginary[f]);<br>zeo_frequency_data[FREQUENCY_HISTORY_SIZE - 1][f + s * F_COUNT] = a;</tt><br><br>Exactly what could be wrong with this is a bit of a mystery.&nbsp; The memory access to <tt>real[f]</tt> is clearly valid, given that the previous line doesn't trigger the problem.&nbsp; ...and <tt>sample</tt>, being a simple variable, can't cause an improper memory access, not to mention that it's not a write and so won't corrupt anything anyway.&nbsp; The only effect is the value of <tt>real[f]</tt>, which isn't accessed outside of the code I've presented.&nbsp; Once in the array on the last line of code, the value is only accessed by the drawing code, but disabling the drawing code doesn't prevent the problem from occurring.&nbsp; <br><br>So I start playing with the math.&nbsp; Removing either <tt>sample</tt> or <tt>real[f]</tt> fails to fix the problem, however, removing both will fix the problem.&nbsp; So I play some more and discover this:<br><br>real[f] = sample + real[f]; // Triggers the problem...<br>real[f] = sample * real[f]; // Corrects the problem...<br><br>I also note that assigning something else to <tt>real[f]</tt> after the problem-inducing line of code causes the problem to disappear, but that may simply be because the optimization removes the previous line of code.&nbsp; <br><br>So I convert the line to a function call, and insert the function in a different file (for reasons to be explained) and end up with this:<br><br><tt>real[f] = main_function(sample, real[f]);<br><br>double main_function(double sample, double real) {<br>  return 1.0 / 32.0 * sample + 31.0 / 32.0 * real;<br>};</tt><br><br>The problem still occurs, which is good.&nbsp; So now I add another function call, and another function in yet another file, to end up with this:<br><br><tt>real[f] = main_function(sample, real[f]);<br>real[f] = easy_function(sample, real[f]);<br><br>double main_function(double sample, double real) {<br>  return 1.0 / 32.0 * sample + 31.0 / 32.0 * real;<br>};<br><br>double easy_function(double sample, double real) {<br>  return 0;<br>};</tt><br><br>In this way, the code is still executed, but the value is discarded, and the line can't be optimized away because, when creating the object code, the compiler doesn't know what the functions it is calling do, and so it doesn't know that the second one doesn't actually depend on the result of the first. <br><br>However, now the code works.&nbsp; So it must be something caused by the calculated value.&nbsp; Exactly what, I can't imagine.&nbsp; I try assigning values like 0, +1000000, -1000000, etc., but none trigger the problem.&nbsp; ...and with the draw code disabled, the problem still occurs.<br><br>So, there's a few lines (the one listed above) which access the value, but none of them make any data-access decisions based on the value.&nbsp; They only perform calculations with it.&nbsp; Math shouldn't cause memory corruption issues, or any issues at all for that matter, since the value is never used for anything besides more math.<br><br>Then I realize the last two lines in the code I listed can be removed without affecting the value, and so I remove them, and the problem continues to exist.&nbsp; I also recall that the line before the problem-inducing line can be removed without fixing the problem, so I remove it too.&nbsp; That allows me to remove the two lines before it which also access the value of <tt>real[f]</tt>.&nbsp; The result is that there's only one line left in the program that accesses <tt>real[f]</tt>, the one which, when removed, makes the problem go away...<br><br><tt>real[f] = 1.0 / 32.0 * sample + 31.0 / 32.0 * real[f];</tt><br><br>...and then I remember from before that if I remove <tt>sample</tt> without removing <tt>real[f]</tt> that the problem remains.&nbsp; So I do that again, and again, the problem remains.<br><br>So I try some variations on the formula...<br><br><tt>              real[f] = 1.0 / 32.0 + 31.0 / 32.0 * real[f]; // Doesn't work.<br>              real[f] = 1.0 + 31.0 * real[f]; // Doesn't work.<br>              real[f] = 1.0 + real[f]; // Works!<br>              real[f] = 1 + 3 * real[f]; // Doesn't work.<br>              real[f] = 1 + 2 * real[f]; // Works!<br>              real[f] = 0.1 + 2 * real[f]; // Doesn't work.<br>              real[f] = 0.1 + 3 * real[f]; // Doesn't work.<br>              real[f] = 0.1 + 1 * real[f]; // Doesn't work.<br>              real[f] = 0.1 + real[f]; // Doesn't work.<br>              real[f] = 1 + real[f]; // Works!</tt><br><br>What the hell is going on here?  At this point I'm not even changing the instructions involved, just the value of the constants used by those instructions.&nbsp; ...and it's all being done to a variable whose result is never used for anything.&nbsp; ...and, not that it should be possible or anything, but it apparently has nothing to do with overflow, given that the second-to-last line works, but the last doesn't.<br><br>So I try variations of <tt>real[f] = X + 2 * real[f]</tt>, using different values for X.&nbsp; <br><br>Values that result in a working program:  0, 1, 2, 4, 5, 8, 9, 10, 13, 16, 17, 18, 20<br><br>Values that result in a broken program:  3, 6, 7, 11, 12, 14, 15, 19<br><br>Seriously, I double-checked.&nbsp; It's repeatable.<br><br>Perhaps it's time I insert a <tt>printf()</tt> to see what the value is turning into...<br><br>X = 3 yeilds 1020847100762815239274396370466657796096<br>X = 7 yeilds 2381976568446568942012167348365083803648<br>X = 19 yeilds 6465364971497829596878297926574421311488<br><br>X = 20, one of the values that fixes the problem, results in a number that just continues to grow in length.&nbsp; Eventually it reaches infinity (or so says the FPU).<br><br>Now it occurs to me that perhaps the memory access error isn't here in this code.&nbsp; Perhaps some other code is incorrectly accessing the memory that is correctly used to store this variable.&nbsp; To test this theory, I replace the line with this:<br><br><tt>if (real[f] != 0.0) printf(&quot;Holy fuck!\n&quot;);</tt><br><br>That gets triggered a lot.<br><br>Just to double-check, I text search the file for &quot;real&quot; and find a variable of the same name in a different set of brackets.&nbsp; I rename the variable, just in case, but the problem remains.&nbsp; <br><br>Then I replace the above code with this:<br><br><tt>if (real[f] != 0.0) {<br>  printf(&quot;Holy fuck!\n&quot;);<br>  real[f] = 0.0;<br>};</tt><br><br>I was hoping to see how often the variable is overwritten, but interestingly, when I do this I never see the &quot;Holy fuck!&quot; message, which is super-interesting because the code addition that prevents &quot;Holy fuck!&quot; from being displayed isn't actually executed unless &quot;Holy fuck!&quot; is displayed.&nbsp; What the fuck?<br><br>I really don't know where to go from here.<br><br>So I continue with my conclusion that the memory corruption is elsewhere.&nbsp; I revert to the earlier &quot;Holy fuck!&quot; code so that the message is displayed again, then begin disabling pieces of code to see if disabling anything else causes the message to go away.&nbsp; What code I find that I can disable isn't responsible, and being less than certain what the problem might be, I'm not willing to start disabling things on a line-by-line basis to tear it down to the bare minimum.&nbsp; So I decide to display the contents of the variables in binary, hoping to see something useful.<br><br><tt>if (real[f] != 0.0) {<br>  printf(&quot;Holy fuck!\n&quot;);<br>  for (int i = 0; i &lt; 8; i++) {<br>    printf(&quot; %02x&quot;, ((unsigned char*) &real[f])[i]);<br>  };<br>  printf(&quot;\n&quot;);<br>  //real[f] = 0.0;<br>};</tt><br><br>However, once again, this puts an end to the problem, so I never see the contents.<br><br>So I try adding the value to the <tt>printf()</tt> for the &quot;Holy fuck!&quot; message, and from that, I get this:<br><br>Holy fuck!  531424756029718528.000000<br><br>It's the very same number in every message.<br><br>So I add more code to assign this number to a variable, then display the number.&nbsp; I get this:<br><br>00 00 00 00 00 80 9d 43<br><br>...and I also get this:<br><br>Holy fuck!  416798398060...and about a hundred more digits.&nbsp; <br><br>So I add this new number into the program to display it in binary, which yields this:<br><br>00 00 00 00 00 00 ec 5c<br><br>The &quot;Holy fuck!&quot; number now changes back to its original value.&nbsp; <br><br>So I count, and see that the message is displayed 128 times.&nbsp; Looking at the code, I see that the opportunity to display it is much more often than that.&nbsp; So I add more to the <tt>printf()</tt> to check the state of the two loop variables, <tt>i</tt> and <tt>f</tt>.&nbsp; <br><br>Then, I see the problem only occurs when <tt>f</tt> is 257.&nbsp; ...and I realize, <tt>f</tt> shouldn't be 257.<br><br><tt>for (int f = 0; f &lt;= F_COUNT; f++) {</tt><br><br>Oops, I guess that should be &quot;&lt;&quot; rather than &quot;&lt;=&quot;.<br><br>Well, now my code works, but...since <tt>imaginary[]</tt> is after <tt>real[]</tt> in the declaration, isn't it after it in memory?  (not that I assume that must be true, but it seems likely)   Checking the pointers reveals that the reverse is true.&nbsp; So what is in the memory that was being incorrectly accessed?<br><br>I check with objdump...<br><br><tt>objdump -t monitor | grep bss | sort</tt><br><pre>0804fac0 l     O .bss	00000808              phase.18449<br>080502e0 l     O .bss	00000808              imaginary.18448<br>08050b00 l     O .bss	00000808              real.18447<br>08051308 g     O .bss	00000004              main_pause_flag</pre>Oh, reverse order, the second most likely order.<br><br>I'm going to have to remember to use objdump next time I suspect a variable is being corrupted.&nbsp; I figured out early-on that it seemed to just be paused, since clicking on the window (the only command the program accepts, to pause and un-pause it) would cause it to process one more data set before pausing again.&nbsp; If I'd looked to see what was near the pause flag, it would have told me the problem right away.&nbsp; <br><br>As for all those weird symptoms...<br><br>The reason the first assignment to <tt>real[f]</tt> caused no problems was because, if you look at the formula that calculates <tt>new_real</tt>, it always results in zero when <tt>real[f]</tt> was zero to begin with.&nbsp; Thus, it writes to the memory, it just doesn't change the value.<br><br>As for <tt>sample + real[f]</tt> vs. <tt>sample * real[f]</tt>, again, the latter fails to change <tt>real[f]</tt> from zero to non-zero.<br><br>As for the various formulas that work vs. the ones that don't...&nbsp; To understand that you have to look up the binary format of a floating point number.&nbsp; Only the first four bytes of the eight byte float overwrite the pause variable.&nbsp; Those bytes are (part of) the mantissa, the exponent is stored in the last two bytes.&nbsp; <br><br>real[f] = 1.0 / 32.0 + 31.0 / 32.0 * real[f]; // Doesn't work.<br>Binary result after 128 interations: 2b f1 76 96 3c 73 ef 3f<br><br>real[f] = 1.0 + 31.0 * real[f]; // Doesn't work.<br>Binary result after 128 interations: 0d e9 f0 bc b8 c4 42 67<br><br>real[f] = 1.0 + real[f]; // Works!<br>Binary result after 128 interations: 00 00 00 00 00 00 60 40<br><br>real[f] = 1 + 3 * real[f]; // Doesn't work.<br>Binary result after 128 interations: 68 69 43 9a 23 59 8d 4c<br><br>real[f] = 1 + 2 * real[f]; // Works!<br>Binary result after 128 interations: 00 00 00 00 00 00 f0 47<br><br>real[f] = 0.1 + 2 * real[f]; // Doesn't work.<br>Binary result after 128 interations: 9a 99 99 99 99 99 b9 47<br><br>...and I'm sure the rest follow the same pattern.<br><br>So what about this?<br><br><div class="block">Then I replace the above code with this:<br><br>if (real[f] != 0.0) {<br> printf(&quot;Holy fuck!\n&quot;);<br> real[f] = 0.0;<br>};<br><br>I was hoping to see how often the variable is overwritten, but interestingly, when I do this I never see the &quot;Holy fuck!&quot; message, which is super-interesting because the code addition that prevents &quot;Holy fuck!&quot; from being displayed isn't actually executed unless &quot;Holy fuck!&quot; is displayed.&nbsp; What the fuck?</div><br>This one is rather interesting.&nbsp; Without the assignment to <tt>real[f]</tt>, it gets moved from the &quot;bss&quot; section, which is for zero-initialized data not included in the executable, to the &quot;rodata&quot; section, which is for pre-initialized read-only data contained in the executable.&nbsp; There, whatever data is located after it, is non-zero, triggering the message to be displayed.&nbsp; Once the assignment is added, it becomes &quot;bss&quot; data again, where once again the pause flag is located after it, and so it is always zero.<br><br>The same thing happens with the code that attempts to display a hex dump of the number, even though that code doesn't write to the number.&nbsp; Both situations don't make any sense.&nbsp; Why move the array to the rodata section, which requires you to initialize it (increasing executable size) just because it isn't written to?  ...and if you're willing to do that, why decide not to do that just because the value is accessed twice instead of once?  I have no idea.<br><br>Anyway, my whole point of this blog post is that I run into problems like this far too often.&nbsp; Something just seems totally out of whack, as if there's a bug in the compiler or something, yet in the end it's just something trivially stupid that I've done to cause the problem.&nbsp; The problem wasn't more than a few lines away from where I was looking, but the &quot;&lt;=&quot; was at one time in the code's history correct, so it didn't stand out as an error, and the fact that the first write to <tt>real[f]</tt> didn't cause a problem seemed to indicate that all of the memory access was valid.&nbsp; <br><br>Lesson learned, I guess.&nbsp; Just because you can write to a variable without triggering a problem doesn't exclude the possibility that you're not writing to it the same thing that was there to begin with.&nbsp; ...and also, just because you do write different values to it doesn't mean that all of the values you choose aren't identical in the few bytes that matter.&nbsp; <br><br>...and I'm not sure this is even worth a blog post, but it's already written, so whatever.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#205</guid>
      <title><![CDATA[EEG, once again!]]></title>
      <author>Pj</author>
      <pubDate>Wed, 25 Apr 2012 11:13:46 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/eeg_once_again.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">I started working on a new EEG circuit like a month ago.<br><br>My previous EEG had two electrodes for each input channel.&nbsp; (As does the OpenEEG project, which I despise.)  This time I wanted to create an EEG which had multiple electrodes with a common reference.&nbsp; I also wanted to test my filter designs in the same way that I tested the Zeo's filter, to make sure they were as optimal as I could make them.<br><br>I realized that, rather than send the test frequencies through one at a time as I did when testing the Zeo, I might just as well send them all at once in one signal.&nbsp; After all, the whole point of Fourier analysis is to separate the frequencies.<br><br>So here's a screen capture of the filter test program:<br><br><center><img src="stuff/filter-shape.png"></center><br>The top half is just the display of the test waveform, the white being the filtered signal, and the red behind it the unfiltered signal.&nbsp; As you can see, there isn't a whole lot of 60 Hz left in there after the hardware filtering.<br><br>The bottom half is a frequency analysis.&nbsp; The vertical bars represent integer frequencies, with 0 being on the left, and the brighter vertical bars marking each 10 Hz interval.&nbsp; The horizontal bars are a logarithmic scale, with each line representing a two-fold increase in signal strength, and the brighter line near the bottom representing a 0-bit input signal, and the line above it a 1-bit input signal (in other words, just barely detectable, and likely in the error range of the ADC).<br><br>The test signal contains every frequency from 0.1 to 1.0 Hz in 0.1 increments, then 1.0 Hz increments up to 10 Hz, then 2.0 Hz increments up to 20, then 10 Hz increments up to 60 or something.<br><br>The peak response is somewhere around 7 Hz.&nbsp; <br><br>I was hoping to allow more DC to pass, but decided there was a limit to how long I was willing to wait for the DC filter to adjust when I move around (a few seconds, rather than a minute), and thus decided that 0.7 Hz being half the amplitude of 7 Hz was good enough.&nbsp; After all, I can always scale the values by their known attenuation when doing frequency analysis.<br><br>For the higher frequencies, it turns out that my desire to pass everything up to 30 Hz unaffected, while filtering 60 Hz to a great extent, is quite difficult.&nbsp; I ended up using a 2-pole butterworth filter, which I then built six of and connected them in series.<br><br>Here's the schematic:<br><br><center><img src="stuff/schematic.png"></center><br><br>All of the op-amps are TL084, which feature JFET inputs, meaning that the require essentially no current from their inputs.&nbsp; You could probably get away with using other op-amps.&nbsp; The TL084 is just my favorite.<br><br>Not drawn is the power supply, which I went all out on in order to remove the 60 Hz interference as much as possible without putting it on batteries.&nbsp; The power supply I used is an AC transformer, connected to a large bank of capacitors and inductors, which then powers a high precision voltage reference and some op-amps which use that high-precision voltage reference to switch some transistors to maintain a constant output voltage.&nbsp; You might just want to use batteries.&nbsp; It's a lot easier if you don't mind the hassle of recharging them.<br><br>The low-pass filter design came from <a href="http://www.ti.com/lit/an/sloa093/sloa093.pdf">Filter Design in Thirty Seconds</a>.&nbsp; I took the low-pass filter in that document and built six of them to use end-to-end.&nbsp; This was necessary because the 60 Hz interference is often much larger than the signal that I want to see, and I want it to be much smaller, but there's only about a factor of 3 between the frequencies I want to see and the 60 Hz which I don't want to see.&nbsp; <br><br>I probably should have given the notch filter a try.&nbsp; Maybe later.<br><br>The amplifier consists of two inverting amplifiers (see <a href="https://www.duckduckgo.com/k/?u=http%3A%2F%2Fwww.stanford.edu%2Fclass%2Fee122%2FParts_Info%2Fdatasheets%2Fop_amp_circuit%2520collection_AN-31.pdf">Op-Amp Circuit Collection</a>) connected end-to-end, such that the end result isn't inverted.&nbsp; Each amplifier amplifies by a factor of 100, for a total of 10,000.&nbsp; The reason for using two amplifiers is that the non-inverting amplifier doesn't draw current from the ground reference on its positive input, which allows me to substitute a voltage stored in a capacitor which is charged via a resistor to the voltage of the output of the amplifier.&nbsp; Thus, if the (average) output becomes high, the capacitor voltage becomes more positive, offsetting the high input voltage and causing the output to move towards zero.&nbsp; <br><br>The first two leads are for the DRL, an idea I stole from OpenEEG.&nbsp; Basically, the problem is that your body floats at some random voltage, which you can't simply offset with a differential input because it's often a voltage too high or too low for the inputs of your amplifier (like +/- 50 volts).&nbsp; ...and while you can connect a ground wire, doing so has two disadvantages:  One is that you now have a low-impedance ground connection to your body, which means if you touch anything electrically charged, you now get shocked, rather than the usual case where you have to touch something electrically charged and something else that is grounded.&nbsp; The other disadvantage is that, at the very small millivolt scale at which we're trying to measure voltages, even the small impedance of that ground connection means that very little current will flow through it to correct the offsets in your body's voltage.&nbsp; So a simple ground connection doesn't completely solve the problem.&nbsp; The DRL circuit solves these problems by using one lead as an input to an infinite-gain inverting amplifier, which then feeds another lead.&nbsp; Because even small differences in voltage are amplified to full scale, the problem of too little current flowing is solved, and because of that, the connection no longer needs to be low-impedance in order to guarantee that your body is maintained at the correct voltage.&nbsp; The two leads aren't completely wasted:  While the DRL output can't be used for anything because the signal there just looks like noise, the input is held at zero volts by the DRL circuit, and thus is the reference point for all other inputs, but as it's always zero volts, you don't actually need to feed it to a ADC.<br><br>Thus, the schematic as drawn shows only one lead for the input.&nbsp; It's still a differential input, as it represents the voltage as referenced from lead 1.&nbsp; It's also possible to simply average together all of the N inputs, and use that average for the DRL input.&nbsp; In the case of an EEG, this creates an artificial input, presumably somewhere in the middle of the brain, to which all other inputs are referenced.&nbsp; I'll probably wire it up like that eventually, but for now I only have the one input channel, and I can't reference it to an average of itself.<br><br>Anyway, here's an example of it at work:<br><br><center><img src="stuff/weird.png"></center><br><br>The number between each pair of beats is the &quot;beats per minute&quot; for that interval, if that interval were repeated for a full minute.&nbsp; <br><br>Have to love those irregular heartbeats.&nbsp; This was recorded about 30 minutes after a quick 5 minutes of vigorous exercise.&nbsp; Before that, it looked similar, but didn't go up anywhere near 80.&nbsp; Probably more like 60 with the occasional 40, in as much as I remember.&nbsp; I decided to try some exercise to see if the problem went away, and it did, even after resting, until I sat up.<br><br>I was reading some junk on the internet the other day that was making me think I have hypothyroidism.&nbsp; The evidence is slim, however.&nbsp; ...but that irregular heartbeat makes me wonder even more.&nbsp; It's like it just wants to beat slower, then once it does, decides that's too slow. I did drink a cup of coffee today.&nbsp; I'll have to avoid caffeine tomorrow and see how it looks the day after that.&nbsp; <br><br>...and speaking of avoiding caffeine...&nbsp; I've found that, rather than consuming a tiny amount of caffeine, consuming none at all seems to help my sleep the most.&nbsp; However, despite all of my testing, I don't feel any better for it.&nbsp; I wonder if I'm just trading one problem for another, like with caffeine I wake up every time I can't breathe, but without it, I continue to sleep and suffocate.&nbsp; I guess once I finish this EEG I can compare caffeinated sleep with decaffeinated sleep and see what the difference is.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#161</guid>
      <title><![CDATA[Laser Projector]]></title>
      <author>Pj</author>
      <pubDate>Tue, 14 Sep 2010 16:05:12 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/laser_projector.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Building a laser projector is something that's always been on my list of things to do.&nbsp; Well, maybe not always, but at least since I got my first laser pointer.&nbsp; <br><br>The other day I found <a href="http://elm-chan.org/works/vlp/report_e.html">this awesome web page</a> where someone explains how they built their own laser projector.&nbsp; The basic idea is simple enough, as it's just two galvanometers with positioning feedback in a servo setup.<br><br>Still a bit too much for me to build, though.&nbsp; I don't have magnets I can glue to a rod and then grind to a nice round shape, nor do I have the grinder, nor does that even sound like something I'd like to try.&nbsp; ...and that capacitive feedback sensor, I probably wouldn't get that to work either.<br><br>So I did this instead:<br><br><center><img src="stuff/projector/projector"></center><br>The mirrors are mounted on two ordinary DC motors, in as much as DC motors with nine rotor contacts and smoother than usual bearings are normal.&nbsp; For positioning feedback, I used infrared interrupter sensors in an analog fashion rather than their typical digital use.&nbsp; The result is that there isn't a whole lot of mirror movement between the full scale of the sensor's ability, but my plan was to use this thing to project onto buildings 100 feet away, and so the fact that it doesn't have a large range of movement actually works well.<br><br>At first the thing couldn't hold the motors still, so I processed the feedback signal through a high-pass filter.&nbsp; Then it could hold it still, but it also wouldn't move it when it should, so I connected a potentiometer between the filtered and unfiltered signals so that I could dial in on the best ratio between the two.&nbsp; There's certainly better ways to do that.&nbsp; Probably the way described on the web site above would work well, but I'm too lazy for all that.<br><br>Anyway, I then designed a simple &quot;star&quot; pattern to display.&nbsp; Here's a photo of my oscilloscope displaying the pattern:<br><br><center><img src="stuff/projector/oscilloscope"></center><br>...and here's what it looks like projected onto the wall using my laser projector:<br><br><center><img src="stuff/projector/results"></center><br>Considering the half-ass way I went about building it, I'm rather surprised it works even that well.<br><br>Here's the same thing with a longer exposure time:<br><br><center><img src="stuff/projector/longexposure"></center><br>Here's a long exposure in the direction of the laser projector.&nbsp; You can see the cone of laser light coming from the projector and extending out the center-right of the photo:<br><br><center><img src="stuff/projector/beam"></center><br>...and since none of those photos look really cool, here's one I took a few days ago:<br><br><center><img src="stuff/projector/amusing"></center><br>For that I just used a 15 second exposure and pointed the laser in every direction I could during the exposure.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#177</guid>
      <title><![CDATA[Stuff I Like]]></title>
      <author>Pj</author>
      <pubDate>Wed, 20 Jul 2011 10:21:33 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/stuff_i_like.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Strange things make me happy.&nbsp; Like this:<br><br><a href="http://www.colbertsuperpac.com/advisory/Advisory-Opinion.pdf">http://www.colbertsuperpac.com/advisory/Advisory-Opinion.pdf</a><br><br>Since you probably aren't aware of what it's about, I will explain:<br><br><a href="http://en.wikipedia.org/wiki/Stephen_Colbert">Stephen Colbert</a> has decided to take advantage of <a href="http://en.wikipedia.org/wiki/Citizens_United_v._Federal_Election_Commission">a recent court ruling</a> to start a <a href="http://en.wikipedia.org/wiki/Political_action_committee">political action committee</a> (PAC), but ran in to trouble when <a href="http://en.wikipedia.org/wiki/Viacom">Viacom</a>, owner of the <a href="http://en.wikipedia.org/wiki/Comedy_Central">Comedy Central</a> network on which <a href="http://en.wikipedia.org/wiki/The_Colbert_Report">his television show</a> airs told him he could not have the PAC because they did not want to disclose the cost of producing his television show in order to comply with laws about disclosing the amount of contributions to the PAC.&nbsp; So, with the help of former FEC chairman Trevor Potter, he requested an advisory opinion from the FEC, as to whether or not mentioning his PAC on his show could be considered news coverage which does not require financial disclosure.&nbsp; <br><br>I'd thought about it a little during the 60 days he waited for a response, and I didn't see any clear and obvious way to decide the matter.&nbsp; On the one hand, his show does cover news items, even if in a comedic way.&nbsp; On the other hand, it's his show, so is it really news or is it just use of his show as a venue for free advertisement?  So I didn't know what to expect the FEC to decide.&nbsp; <br><br>So when I read the opinion of the FEC, I was surprised to see just how well they dissected the problem into individual components, then approached each component in a way that made it clear that they had come to the correct decision.&nbsp; I wasn't expecting that there could be a clear decision, yet here it was, all laid out in easy-to-digest pieces, and it all made perfect sense.&nbsp; It was amazing.<br><br>On several occasions I've come across a random essay I've written years earlier and I always find it a pleasure to read.&nbsp; It doesn't matter that it was so long ago that I can barely remember that I wrote it.&nbsp; I read what I wrote, all of the arguments make sense and cover the argument from every angle I can imagine, and the conclusion at the end seems like the only one that anyone could logically come to.&nbsp; I suppose many would say that it's simply because I wrote it, but I'm talking about things so long forgotten that I feel like I'm reading someone else's words.&nbsp; If I needed time to change my mind, I definitely had it, yet my opinion is identical to what it was.&nbsp; ...or at least it is after I read the awesome arguments I present.&nbsp; <br><br>Reading that advisory opinion was like that.&nbsp; I have no idea what compelled me to read it in the first place, but I'm glad I did.&nbsp; It's nice to occasionally have some reassurance that the world isn't composed entirely of <a href="http://en.wikipedia.org/wiki/Philosophical_zombie">philosophical zombies</a>.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#200</guid>
      <title><![CDATA[GCC sucks less at compiling math equations!]]></title>
      <author>Pj</author>
      <pubDate>Wed, 4 Apr 2012 16:51:14 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/gcc_sucks_less_at_compiling_math_equations.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Today I noticed GCC using the fsqrt instruction in a function, rather than calling a sqrt() function which would certainly just use the instruction.&nbsp; It was so much more optimized than I recall seeing in the past that I felt inclined to write a simple function to examine how well it generates code now.<br><br>So I wrote this function:<br><br><div class="block"><pre>void whatever(double *x, double *y, double a) {<br>  double t;<br>  t = *x * cos(a) - *y * sin(a);<br>  *y = *x * sin(a) + *y * cos(a);<br>  *x = t;<br>};</pre></div><br>In case you're interested, this is the equation to rotate an (x, y) coordinate around the origin by the angle a.&nbsp; The temporary variable is necessary because both the new x and new y values need to be calculated from both of the original x and y values, and so we can't change either until we've calculated both results.&nbsp; <br><br>Here's the code that GCC generated for this function, in NASM syntax because GAS is fucking unreadable:<br><br><div class="block"><pre>0804a460 &lt;whatever&gt;:<br>  0804a460  55                push ebp<br>  0804a461  89E5              mov ebp,esp<br>  0804a463  56                push esi<br>  0804a464  53                push ebx<br>  0804a465  83EC20            sub esp,byte +0x20<br>  0804a468  8B5D08            mov ebx,[ebp+0x8]<br>  0804a46b  8D45F0            lea eax,[ebp-0x10]<br>  0804a46e  DD4510            fld qword [ebp+0x10]<br>  0804a471  8D55E8            lea edx,[ebp-0x18]<br>  0804a474  8B750C            mov esi,[ebp+0xc]<br>  0804a477  DD1C24            fstp qword [esp]<br>  0804a47a  8954240C          mov [esp+0xc],edx<br>  0804a47e  89442408          mov [esp+0x8],eax<br>  0804a482  E861EBFFFF        call dword 0x8048fe8 &lt;sincos@plt&gt;<br>  0804a487  DD45E8            fld qword [ebp-0x18]<br>  0804a48a  DD45F0            fld qword [ebp-0x10]<br>  0804a48d  DD03              fld qword [ebx]<br>  0804a48f  DD06              fld qword [esi]<br>  0804a491  D9C1              fld st1<br>  0804a493  D8CB              fmul st3<br>  0804a495  D9C4              fld st4<br>  0804a497  D8CA              fmul st2<br>  0804a499  DEC1              faddp st1<br>  0804a49b  DD1E              fstp qword [esi]<br>  0804a49d  D9CB              fxch st3<br>  0804a49f  DEC9              fmulp st1<br>  0804a4a1  D9C9              fxch st1<br>  0804a4a3  DECA              fmulp st2<br>  0804a4a5  DEE1              fsubrp st1<br>  0804a4a7  DD1B              fstp qword [ebx]<br>  0804a4a9  83C420            add esp,byte +0x20<br>  0804a4ac  5B                pop ebx<br>  0804a4ad  5E                pop esi<br>  0804a4ae  5D                pop ebp<br>  0804a4af  C3                ret</pre></div><br>Wow...<br><br>On the one hand, I'm impressed to see that it figured out that all of the sin() and cos() use the same angle, and thus it only needs to calculate the values once.&nbsp; I'm also impressed to see that it realizes that both values can be calculated at once, and calls a sincos() function.&nbsp; It also doesn't utilize a temporary variable, since the values have to be copied into the FPU stack anyway, and so the original x and y values are available even as the old ones are overwritten with the results of the two equations.&nbsp; Even the series of instructions to solve the equations are nicely written.<br><br>However, why the fuck is it calling sincos()?  Ever since the FPU was introduced it's had a fsincos instruction which does exactly the same thing.&nbsp; Indeed, it isn't even possible to calculate the sine or cosine alone as the fsincos instruction is your only choice and so you have to calculate both values at once.&nbsp; So why is it calling sincos()?  It obviously expects that I have an FPU as it has planted the call to this function in the middle of a bunch of FPU instructions, so it can't be expecting that maybe the instruction isn't available.&nbsp; So what the hell?<br><br>I can't get over how absurd this is.&nbsp; I feel compelled to write a color-coded example, so here's what the above code does written in plain english:<br><br>The code above first sets up the stack as all functions must do upon entry and saves registers according to the calling convention.&nbsp; It then loads the angle into the FPU, <font color="red">and from there stores it onto the CPU stack.&nbsp; It also places onto the CPU stack two pointers to local variables.&nbsp; Then it calls sincos().</font>  <font color="blue">In sincos(), the usual stack manipulation will occur, then the angle will be loaded from the CPU stack into the FPU stack.</font>  <font color="green">Then the FPU instruction fsincos will be used to calculate the sine and cosine of that angle.</font>  <font color="red">Then the sine and cosine will be stored from the FPU stack into the two pointers which were passed as parameters to sincos().&nbsp; Then sincos() will undo its stack manipulation and return.</font>  <font color="blue">Now, the code above loads the sine and cosine values into the FPU stack from the local variables they were stored to by the sincos() function.</font>  It then loads the x and y values from their pointers into the FPU stack.&nbsp; Finally, the two equations are solved, and the results are written to the pointers given to the function as parameters.&nbsp; Finally, the stack setup is reversed, and the function returns.<br><br>The ridiculous thing about this is that everything above in red is the inverse of everything in blue.&nbsp; All of the red and blue can be removed and the exact same fucking thing will happen, but without a bunch of unnecessary movement of data.<br><br>...but, whatever.&nbsp; I always knew GCC was bad at compiling math.&nbsp; I'm just thrilled to see that it no longer calls a function every time I use sqrt().<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#203</guid>
      <title><![CDATA[FORTRAN is the answer]]></title>
      <author>crunge</author>
      <pubDate>Thu, 5 Apr 2012 21:50:22 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/fortran_is_the_answer.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">As I understand it, FORTRAN is still alive and well because it tends to do smarter things when working with math. I don't know if that's limited to large data sets or what. I know there are fast math libs out there, don't know if it still would be faster jumping into the other code.<br><br>If you really feel like wasting more time in assembly, you might be able to get something out of SIMD.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#162</guid>
      <title><![CDATA[More Laser Projector Pictures]]></title>
      <author>Pj</author>
      <pubDate>Tue, 14 Sep 2010 22:54:09 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/more_laser_projector_pictures.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">After screwing with the laser projector for a while, I got it to work a little better, mostly by using a bit of fishing line glued to the mirrors to pull them in one direction.&nbsp; Each had a specific direction it had to be pulled in, and so I think this helped because of the weak -12 volts provided by my power supply, and pulling the mirror in one direction means that it relies mostly on the stronger +12 volt supply.<br><br>Anyway, this is what it looks like now:<br><br><center><img src="stuff/projector/star.jpg"></center><br><center><img src="stuff/projector/arrow.jpg"></center><br><center><img src="stuff/projector/square.jpg"></center><br>The lines aren't exactly straight, as made obvious by the square, but unlike before, the errors it makes now are repeated identically for each frame, and so at least the image is stable.<br><br>On the web site I linked to before, I found a few of that person's pictures included with his image editor, and so I tried them out on my projector.&nbsp; My projector is way too slow for such complex images, but that didn't stop me from using a 15 second shutter time to make visible something that is being drawn so slowly that it is otherwise unrecognizable.&nbsp; There are some stray lines included since my system doesn't have the ability to turn off the laser.<br><br><center><img src="stuff/projector/appi.jpg"></center><br><center><img src="stuff/projector/peace.jpg"></center><br><center><img src="stuff/projector/laser.jpg"></center><br><center><img src="stuff/projector/hp.jpg"></center><br><center><img src="stuff/projector/tek.jpg"></center><br>I've been planning to use DC motors the next time I build a CNC mill, and I've had people tell me that I have to use stepper motors because DC motors won't be capable of fine positioning.&nbsp; Well, at a distance of 12 inches, the projected image is only 1 inch wide, which means I'm drawing these things with only 5 degrees of movement.&nbsp; I only need positioning accurate to within 36 degrees for my CNC mill, whereas it seems I'm getting far better than 1 degree positioning with this laser projector.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#198</guid>
      <title><![CDATA[Light, sugar, and caffeine.]]></title>
      <author>Pj</author>
      <pubDate>Sat, 28 Jan 2012 00:38:47 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/light_sugar_and_caffeine.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Continued to go outside for a walk every day.&nbsp; Seemed like it might be helping a little for a while, but then after about five days without seeing the sun due to overcast skies, my sleep cycles went back to crazy nonsense.&nbsp; So overcast brightness isn't enough, and imitating direct sunlight with indoor lighting would cost too much and produce too much heat.&nbsp; So I guess I have to wait until May and try again.&nbsp; <br><br>Even Wikipedia indicates in some random article that about 3000 lux is what is used for light therapy for sleep disorders (presumably imitating the brightness of overcast days), and so my indoor lighting levels should be sufficient.<br><br>However, what benefit I received, even during the days with direct sunlight, weren't all that great.&nbsp; It was nice knowing what time I should wake up and go to sleep, but I still spent much of the day (more than usual) just lying in bed too tired to do anything, and I still frequently awoke for hours during the night.&nbsp; However, I still want to give it more of a try once summer comes and I can count on seeing the sun on a more regular basis.<br><br>I've continued to avoid sugar.&nbsp; My weight is now 223 whereas it was 243 when I started.&nbsp; Probably would have lost more weight except that my sister keeps cooking meals, and she always cooks far more than everyone should eat.&nbsp; <br><br>I checked my blood pressure, since it's part of the &quot;toxic fructose&quot; theory that fructose even leads to high blood pressure.&nbsp; It was up around 160/100 when I started.&nbsp; It's now 110/66, with a pulse rate of 60.&nbsp; I suppose some of that could be from going for a walk everyday.&nbsp; Regardless of the cause, the magnitude of that change is extraordinary.<br><br>Avoiding caffeine entirely fails to continue the improved sleep I see after avoiding it for only a few days.&nbsp; Eventually my sleep becomes just like it was before, and to get that improvement again, I need more caffeine and then a few more days without the caffeine.&nbsp; I may have to try some really small doses, like 20 mg (like 1/3 of a can of soda), and see if there's some positive benefit from that.<br>]]></description>
    </item>

    <item>
      <guid>http://www.ecstaticlyrics.com/pinnwand/#194</guid>
      <title><![CDATA[Politics: YouTube Videos about Money and Debt]]></title>
      <author>Pj</author>
      <pubDate>Sun, 30 Oct 2011 00:59:25 GMT</pubDate>
      <link>http://www.ecstaticlyrics.com/pinnwand/messages/politics_youtube_videos_about_money_and_debt.html</link>
      <description><![CDATA[<base href="http://www.ecstaticlyrics.com/pinnwand/messages/">Some shit I found on Slashdot, in case anyone happens to like watching hour-long videos:  (Feel free to stop watching when each video starts suggesting possible solutions, as that's where the fun ends.)<br><br><a href="http://www.youtube.com/watch?v=Dc3sKwwAaCU">http://www.youtube.com/watch?v=Dc3sKwwAaCU</a><br><a href="http://www.youtube.com/watch?v=rCu3fpg83TY">http://www.youtube.com/watch?v=rCu3fpg83TY</a><br><br>The first is an interesting-enough explanation of how fractional reserve banking works, which does well with a nice story of a goldsmith deciding to scam everyone.&nbsp; The second really isn't worth watching unless you watch the first, since it doesn't try very hard to make what it says believable, and so if you don't already believe it, it likely isn't going to convince you of anything.<br><br>However, the second video is still interesting because it proposes an answer to a question I've had for some time:  How the hell can the economy just stop working?  People need stuff, people can work to create stuff, and as long as people can meet each other's needs, there's no logical reason why an economy should fail.&nbsp; That is, until you realize the whole damn thing is based on debt rather than wealth, as the first video explains.&nbsp; <br><br>If the economy were based on wealth, then even with a completely broken economy, some farmer could still use some of his wealth (what land and seeds and machinery he has) to grow some food.&nbsp; Other people could use their wealth (materials they have on hand) to make clothing or build houses.&nbsp; Then everyone could trade what they have for what they need.&nbsp; Thus, economy failure should be impossible.<br><br>However, since it's all based on debt, a farmer can't just grow some food.&nbsp; He has to make mortgage payments on his land, buy seed, hire workers, pay the people who own the harvesting equipment to harvest it, etc.&nbsp; Similarly, someone can't just make clothing.&nbsp; They have no materials on hand.&nbsp; We do everything based on debt, so when someone wants to make more clothes, they borrow some money to buy fabric, pay workers, etc., then repay the loan with their profits.&nbsp; So if the economy dies and money stops flowing, no one can do anything, even though we all know that if we just kept doing what we were doing the day before, life would go on like it always had, just without the money.<br><br>The first video really makes a lot of sense out of the otherwise confusing numbers on this site: <a href="http://www.usdebtclock.org/">http://www.usdebtclock.org/</a>  It currently indicates $47,702 of debt per citizen.&nbsp; That includes not just national debt, but all debt, including mortgages, business loans, etc.<br><br>When I first saw that number a few months ago I wondered how the hell it was even possible.&nbsp; Who is loaning all of that cash?  Those videos explain it rather well.&nbsp; No one is loaning that cash because the cash doesn't exist.&nbsp; Our whole damn economy is based on everyone being in debt.<br><br>I always thought those people wanting to return to using gold as money were just a bit crazy.&nbsp; After all, as long as people accept money for stuff, it works just as well.&nbsp; However, when you consider that banks are allowed to create money, using something else for money, something that people can't just create more of, does seem rather attractive.&nbsp; ...but it ignores the main problem.&nbsp; Sure, creating money whenever someone wants a loan is a problem, but even without doing that, loans are still a problem.<br><br>I've said before that I think loans are inherently evil, and I think those videos, the first in particular, show a side of that evil that even I hadn't really considered before.&nbsp; I've always been concerned with the aspect that loans eliminate the hard wall that people run up against when they run out of money, forcing them to realize that they need to start living differently, and also that loans make it easier for people to pay a lot of money for things, reducing the free-market force that keeps prices low.&nbsp; The videos show that loans as they exist today aren't even made of real money, but instead are just the result of the government authorizing banks to create money whenever someone asks for it, then collect interest on the money loaned, even though that money didn't really exist before it was borrowed and so the bank is receiving interest despite not really having to part with very much money at all.&nbsp; The bank may only get 10% interest, but since the bank is only required to have 10% of the money it loans to you, it's technically getting 100% interest on the money it has invested in making that loan to you.&nbsp; ...and, even if the banks weren't allowed to do that, there's still the problem of interest which the videos do well at showing to be a bad idea, yet in the end, fail to condemn as something that should be illegal.<br><br>However, nevermind people getting rich for illegitimate reasons.&nbsp; The big problem is the economy grinding to a halt, and the source of that isn't people getting rich by illegitimate reasons, it's people having no resources on hand to do anything because loans have allowed them to reduce their capital to negative values, and so if credit dries up, no one can do anything.&nbsp; Indeed, loans may well have required this, since any business that doesn't choose to go this route will be at a disadvantage to those that do take advantage of loans.<br><br>Let's just make interest illegal.&nbsp; Then people will stop making loans except in the most honest &quot;I just want to help out a friend&quot; cases, people will then be forced to maintain positive amounts of capital if they want to stay in business, and then even if all of the money in the world disappears overnight, people will still be able to do things and so the economy will be able to start itself up again the next day.<br>]]></description>
    </item>

  </channel>
</rss>

