The ipad is Not the Kindle Killer
The inter-webs have been abuzz about the revelation of Apple's new ipad, and as always, I'm late to the blogging party. Now I'm no Apple fanboy, and I'm not particularly impressed by Apple's new slate. Personally I wouldn't buy it, but I'm sure there are tons of people out there that would love to own one. The one thing however, that has really been bugging me lately, is how so many people are proclaiming the ipad to be the Kindle killer, and that Amazon (and all other e-book reader makers) should just close up shop. Yes, the ipad is capable of providing so many more services then the Kindle, such as full web browsing, office programs, and movie playing capabilities, things that the Kindle cannot possibly offer. But Apple fans are forgetting that the reason that people buy Kindles and other e-book readers, is so that they can read books, and not browse the web.
E-ink, the display technology behind most e-book readers, is an amazing technology, and not just because of its superior battery life, but because reading it is like reading a newspaper. Anyone who has read plain text on a computer screen for hours at a time, knows that it is not a particularly fun experience. Back-lit screens are stressful on the eyes after long periods of time, whereas reading a good-old-fashioned paper book is a much easier experience. I own several e-books and I actually read Stephanie Meyer's God-awful Twilight book on my computer screen and it was not an experience that I want to repeat, not just because of the terribleness of the book but also because of how my eyes were starting to burn from staring at a back-lit screen for so long. Now I have a friend that says he likes to read books on his iphone for extended periods of time, and I'm fairly certain that hes either a freak of nature, or a bold faced liar. But aside from the scarce masochistic few who enjoy burning their retinas out staring at glowing boxes, most everybody else would rather read paper books.
E-ink has allowed for electronic reading devices that are easy and comfortable to read on. This is something that the multi-use ipad does not offer, and it is the reason that dedicated e-book readers like Amazon's Kindle aren't going anywhere just yet. I don't mean to imply that the ipad is doomed to failure, but rather that the ipad is a device meant to do many things and cannot compete with dedicated e-book readers like the Kindle.
Intel FDIV Bug
A few years or so back, I put up a bunch of my high school and early college papers on this blog (they're under the "literature" category). Its a sad state of affairs when looking back my high school papers, that I realized my writing skills were significantly better back in high school. But anyways, heres a paper I wrote for my engineering ethics course. Its not my best work, and it certainly lacks the finish of my old high school stuff, but its passable.
To the Intel Corp. Board of Directors: A Post Mortem Report of the Pentium Flaw
Abstract
The floating point division flaw in the original Intel Pentium CPU, which resulted in some floating point division operations being calculated improperly, was a result of a few poor engineering decisions and while avoidable, was not condemnable. The subsequent decisions made by Intel executives, to keep the flaw hidden and then to downplay its importance, were however, morally flawed. While Intel executives adhered to a utilitarian ethical framework, they forgot to consider the impact their decisions would have on Intel’s public image. Had Intel executives followed a combination of rights and utilitarian ethics, where the rights of the customer are upheld while the company’s wellbeing is still valued, executives would have reached the correct decision, which was to offer a full “no questions asked” replacement policy at the very first discovery of the flaw.
The Pentium “FDIV Bug”
Given certain types of input data, the floating point division instructions on the original Intel Pentium CPU would generate slightly erroneous results. This result was dubbed by the public as the “FDIV Bug,” as one of the assembly language instructions affected by the bug was the FDIV instruction. Although Intel initially attempted to keep information regarding the flaw hidden, it eventually became public knowledge. The subsequent actions of Intel executives regarding their handling of the flaw were morally questionable and ultimately resulted in great damage being done to Intel’s public image. A different set of ethical frameworks would have allowed Intel executives to have reached the correct decision.
Using the basic Microsoft Windows calculator, a Pentium user could check for the presence of the flaw by performing the following calculation:
(4195835 * 3145727) / 3145727
The expected result of dividing a number by itself is one, so the equation above should yield a result of 4,195,835 but the flawed Pentium Floating Point Unit (FPU) produced a value of 4,195,579; an error of 0.006%. Not all calculations performed by the FDIV instruction on a Pentium CPU were incorrect however. The occurrence and degree of inaccuracy of the floating point division calculations were highly dependent on the input data and specific divide instruction used, and in most cases, the flaw was not apparent at all. According to Intel Corp., the flaw would only be encountered once every 27,000 years under normal use, although other groups have produced significantly different failure rates.
The “FDIV Bug” did not affect Intel CPUs predating the Pentium, as the flaw was a defect in a new algorithm that was intended to provide improved floating point performance over the Intel 486 (the predecessor to the Pentium). The Pentium used a new radix 4 SRT algorithm (named after its creators Sweeney, Robertson, and Tocher) in its floating point division operations, which required the use of a lookup table to improve calculation speed (Intel Corp. Section 4). This lookup table was generated prior to assembly and then loaded into a hardware Programmable Lookup Array (PLA) on the Pentium chip. However, the script which downloaded the lookup table into the PLAs had a bug in it that caused some lookup table entries to be omitted from the PLAs. Consequently, floating point division instructions that required the missing entries from the lookup table would produce erroneous values. This flaw has since been fixed and the “FDIV Bug” is no longer apparent in newer Intel CPUs.
The Pentium flaw should have been easily discoverable in early testing of the CPU, but there was also a mistake in Intel’s proofs for the Pentium FPU. Intel engineers attempted to simplify testing, and assumed that the sign (“+” or “-“) of a number doesn’t enter into division operations except in the last step. Thus, the proof for the Pentium only checked half of the PLA, and assumed (incorrectly) that the other half of the PLA was simply the mirror image of what was checked (Price P. 2). Unfortunately, the untested half of the PLA contained the missing entries. The two easily discoverable flaws, one in the PLA loading script and the other in the PLA proof, conspired to hide each other from Intel engineers so that the Pentium’s flaw was not discovered until after production of the CPU began.
Events Surrounding the Flaw
Intel Corp. discovered the flaw in the Pentium’s floating point unit through testing, in June of 1994 (after production of the chip), but chose to keep the information private instead of disclosing it to their customers (Markoff). Although Intel modified the design of the Pentium, the modified chips did not begin to reach the market until November of 1994, and the sales of flawed chips were not halted. Dr. Thomas R. Nicely of Lynchburg College also independently discovered the “FDIV Bug” in June of 1994 and attempted to bring it to the attention of Intel Corp. in October of that year, whereupon an Intel representative confirmed the existence of the flaw and then ceased to provide Dr. Nicely with any more information (Nicely). Nicely then proceeded to make the Pentium floating point unit’s flaw known to the public via e-mail, causing news of the Pentium flaw to spread quickly. Concerned Pentium owners who learned of the flaw were told by Intel that the flaw was inconsequential and that no replacement policy was being offered.
Miyata 914 – Acquisition and Review
About how I acquired a Miyata 914
For the past three months, while on my way to class, I've been walking past a wheel-less bike chained to a bike rack underneath an overhang. The bike's distinctive bright green saddle was pretty much the only speck of color amidst a sea of dirty Huffys, so it was hard to miss. One day, I happened to catch a closer glimpse of the green-saddled bike and was surprised to notice that it was a Miyata (I have a soft spot for Miyatas, since I already own one), and closer inspection revealed it to be a Miyata 914. I spent several minutes examining the Miyata and noticed that aside from the thick layer of dust and grime that coated it and the lack of wheels, it was in surprisingly good condition. I started to wonder if the owner of the Miyata had graduated and forgotten his bike, or had simply abandoned it after the wheels were stolen. On the off chance that the latter was true, and hoping that the Miyata's owner still walked the same route to class, I left a note asking the owner to contact me if he had any wish of selling.
My note was gone the next day, and I received an e-mail from the Miyata's owner by the end of the week, saying that he was considering selling his bike and would I make an offer? Betting that any man who puts a kick-stand on a semi-pro bike (the atrocity!) and leaves it outside for three months, probably doesn't realize the worth of a good, splined, triple-butted Miyata CrMo steel frame, I offered him a low-ball offer of $50; high enough to tempt him into selling, but still low enough to make it a bargain buy. We eventually settled on $75, which was higher then I would have liked, but still pretty decent. I've been told that the Miyata 914 has the same frame as the top-of-the-line Miyata Team, but with slightly inferior components, and I saw a NOS 1990 Miyata Team selling for $600 on ebay, which makes the $65 I paid seem like daylight robbery. I think given the condition of the Miyata that I purchased, it could have fetched close to $200 on craigslist.
My initial suspicions about the owner were confirmed when I met him: he did not appear to be a cyclist and didn't realize the full worth of the Miyata 914. Strangely enough, he was several inches shorter then me (I'd put him around 5 foot 7 inches), which would have meant that ridding the 60 cm Miyata must have been extremely awkward for him.
As soon as money and bike exchanged hands, I raced home, threw some newspaper down and set up my bike stand in the middle of the living room (thank God my roommates weren't home...). I started with just cleaning the bike off first, and as soon as the dirt started to fall away, I began to realize that the 914 was actually in better condition then I had thought; the paint was only scratched in a few places, and the chainrings looked brand new.
Back to School
Last quarter was probably my worst quarter ever. So of course, I have resolutely set out to change my habits and turn my academic performance around. Of course, its only the second day of school now, but I think my first day of class was exciting enough to deserve some blogging.
This quarter is momentous as it marks the first time in a year that I have enrolled in a non-engineering course. In this case, I'm currently enrolled in a statistics and a math class (among other classes). So the thing that astounded me upon first walking into my statistics classroom, was that there were girls in my class, more specifically, there were a lot of girls in the classroom (around 50%). This is in stark contrast to most of my engineering courses, where a classroom that is 20% female is considered to have an unusually high female to male ratio. I've had an electrical class with 14 guys and 0 girls, and a computer science class with 19 guys and 1 girl. Walking into my stats class, I felt as though I had entered another realm.
My first day proceeded to get more and more interesting. I spent fifteen minutes sitting in what I thought was my computer architecture class, before I realized that I was in the wrong class. Checking my schedule, I realized that my computer architecture class is on Tuesdays and not Monday (on the plus side, I was in the right room). Too embarrassed to push my way through the five people obstructing my path to the aisle, and walk out during the middle of class, I sat through the rest of the lecture, growing more and more confused about automata theory (a subject I was totally unqualified to understand).
But on the home front, I discovered that one of my roommates had left a pan of some sort of cooked food in the fridge over winter break, which meant that it was nearing almost four weeks old. So of course, the unidentifiable contents of the pan are now sporting a pretty coating of green and white mold. I stated how disgusting it looked and told my roommate that he should probably throw it out. Whereupon, he removed it from the fridge and placed it in the sink. The pan has since migrated to the countertop, and it appears that the green mold is now starting to outstrip the white mold (Go Green!). As of noon of today, the pan and its contents were still sitting on the countertop. Some part of me finds it extremely revolting, but another part of me is fascinated and wants to take pictures. I've decided to just not look at it until he throws it out.
My Goodness, My Guinness!
We took a tour of the Guinness storehouse in Dublin, Ireland, last Monday (December 21st). I highly recommend the Guinness tour, as it is great fun, and relatively inexpensive considering that it comes with free beer. Now up until two weeks ago, I disliked the taste of alcohol, and most especially hated the taste of beer. But after having spent some time in Europe, I've managed to develop a taste for various wines, and now even beer. Apparently, all the beers that I've tried previously were cheap and of poor quality, and were therefore not particularly good. While at the Guinness factory, I easily polished off a pint of Guinness draft in record time; a stark contrast to my previous attempts with beer, which usually ended up with me retching after one sip.
After finishing the tour, we went up to the top floor of the storehourse, where the gravity bar is, to enjoy our free pint of Guinness. The bar has glass walls and offers a great birds-eye view of Dublin. We weren't at the bar long however, before we happened to notice that the view behind us was being obscured by huge clouds of gray smoke. We wondered briefly about the origins of the smoke, but being tourists, we quickly dismissed it as probably being normal to Dublin (Maybe someone should tell Copenhagen? I dunno...). A few minutes later, one of the bartenders made an announcement, since apparently several people had asked her about the smoke, saying that everything was under control, that we had nothing to worry about, and that nothing was wrong. She made similar annoucements two more times. After the third announcement, she proceded to lead the bar's occupants in a cheerful Irish song. Now, when a young child vehmently assures their parents that they have done nothing wrong and have been perfectly angelic, the child's parents will imediately start checking the integrity of all breakable items in the house. Much in the same way, we knew something was amiss.
|
|---|
After leaving the factory, we uncovered the truth behind the mystery of the billowing grey clouds: one of the Guinness storehouses had caught fire. Fortunately, it was only an old empty storehourse and nobody was hurt in the blaze, but most importantly, no beer was lost in the fire. Many of the tourguides, bar tenders, waiters, and other Irish locals that we met later on in Ireland, expressed to us their distress of the Guinness storehouse fire. Everyone seemed especially glad that none of the beer had been burned in the fire. I imagine though, that if the blaze hadn't been contained as successfully and had spread to occupied storehouses, December 21st would have attained Sabbath-like importance and would have been remembered in Ireland as the day Guinness caught fire. And then I could have told people, "I was there."
Knight’s Tour in Lisp
For those of you unfamilar with the Knight's tour, here's a brief overview of the problem. The Knight's Tour invovles placing a knight on a chessboard and then having the knight move to each and every square on the chessboard once and only once. There are a suprisingly huge number of possible paths that a single Knight can take on a standard chessboard so of course, a blind, exhaustive search is generally out of the question.
The program I have written below explores the Open Knight's Tour, where the knight simply has to reach each and every square once and only once (the Closed Tour would add the additional requirement that the knight end on the square he started on). I will admit that my Lisp code isn't exactly the best or the most efficient, but it works fairly deccent. My method of solving the tour, uses backtracking (which is very similar to Depth First Search) and a herustic known as Minimum Remaining Value. This herustic is sometimes known as Warnsdorff's algorithm when used in the Knight's Tour. Warnsdorff's algorithm selects as the knight's next move, the square that would present the fewest possible moves following the move to that square. Essentially, the herustic is trying to eliminate dead end's earlier on. And so here's my code (most of which is comments, [Hey, it was written for a class]):
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; FIND-KNIGHTS-TOUR2 ;;; ;;; using minimum remaining value herustics (aka most constrained variable) ;;; ;;; ;;; ;;; on my laptop, this implementation can find a solution to ;;; ;;; 100x100 board, starting from (1 1) in under three minutes ;;; ;;; and can solve 50x50 in about 16 seconds on SEAS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; you can run the knights tour with: ; (find-knights-tour ([rows in board] [cols in board] [row_pos] [col_pos]) (setq steps 0) (setq visited-list ()) ; generate a list of all possible moves for knight ; given that current position of knight is (row col) ; note that this function will generate "wrong" move values, like ; moving off the board or moving to an old spot. ; ; function get_values(number:x number:y):((num num) (num num)) (defun get_values (row col) (list ; there are at most eight possible move values (list (+ row 2) (+ col 1)) (list (+ row 2) (- col 1)) (list (+ row 1) (+ col 2)) (list (+ row 1) (- col 2)) (list (- row 2) (+ col 1)) (list (- row 2) (- col 1)) (list (- row 1) (+ col 2)) (list (- row 1) (- col 2))) ) ; val is a list of possible move values for a knight variable ; and should be generated by get_values function ; m_row is max number of rows in the board ; m_col is max number of columns in the board ; ; test_valid_values will return a list containing only the valid ; values allowed, removing those values that have already been ; visited and are not on the board ; ; function test_valid_values( ; ((num num) (num num) ):vals ; number:m_row ; number:m_col):((num num) (num num) ) (defun test_valid_values (vals m_row m_col) (let ; grab the first value out of the vals list ((v (car vals))) (cond ((null vals) ()) ; test for out of bound values, or already traversed ; if value is out of bound, remove it (cdr vals) ((or (> (car v) m_row) (<= (car v) 0) (> (cadr v) m_col) (<= (cadr v) 0) (list_member v visited-list)) (test_valid_values (cdr vals) m_row m_col)) ; value is valid, add to our "valid" list (t (cons (car vals) (test_valid_values (cdr vals) m_row m_col))))) ) ; check if "l" is a member of "visited" ; return 't' if so, 'nil' otherwise ; ; function list_member( ; (number number):l ; ((num num) (num num) ):visited) :t/nil (defun list_member (l visited) (cond ((null visited) nil) ((equal (car visited) l) t) (t (list_member l (cdr visited)))) ) ;minimum remaining value herustic, or the most constrained variable ;instead of just returning randomnly arranged list of possible moves from ; current location (as in above without herustics) arrange possible moves ; in the list so that the move that will offer the least number of moves in ; the next iteration comes first, with the move that offers the most of ; moves coming last in the list ; ;function min_remaining_val(number:m_row number:m_col): ; ((number number) (number number) ) (defun min_remaining_val (m_row m_col) (let ; get valid values ((vals (test_valid_values (get_values (car (car (last visited-list))) (cadr (car (last visited-list)))) m_row m_col))) ; then call call mrv_helper to attach assign a value to each move ; mrv_sort to arrange moves (mrv_sort (mrv_helper vals m_row m_col)) )) ; determines number of possible moves allowed if we move to a position in ; the vals list ; ; function mrv_helper( ; ((num num) (num num) ):vals ; number:m_row ; number:m_col) : ; ((num (num num)) (num (num num)) ) (defun mrv_helper (vals m_row m_col) (let ((len ; calculate the number of possible moves from a position in the ; "vals" list (length (test_valid_values (get_values (car (car vals)) (cadr (car vals))) m_row m_col)))) (cond ; if no more moves in "vals", just return it and done ((null (cdr vals)) (list (cons len (list (car vals))))) ; else add move and length value to list and keep recursing (t (cons (cons len (list (car vals))) (mrv_helper (cdr vals) m_row m_col))))) ) ;finds the move with the minimum value in the list "vals" ;i.e. if "vals" is ( (1 (2 4)) (2 (5 2)) (4 (3 2)) ) ; then min_vals would return (1 (2 4)) because its move value is "1" ; ;function min_val( ; ((num (num num)) (num (num num)) ):vals) : ; (num (num num)) (defun min_val (vals) (cond ; base case, return the only move in "vals" ((null (cdr vals)) (car vals)) (t (let ; calculate the min_val in the rest of the list ; store it in "p" ((p (min_val (cdr vals)))) (cond ; if the current minimum value is less then previous ; min val, then use current min val ((<= (car (car vals)) (car p)) (car vals)) ; else use previous min val (t p))))) ) ; remove from list 'l' the element that matches 'r' ; this is because we are not allowed to use "remove" function ; ;function remove_list(list:r list:l):list (defun remove_list (r l) (cond ; if equal, then done ((equal r (car l)) (cdr l)) ; reached the end and couldn't find a match ((null (cdr l)) l) ; else keep recursing (t (cons (car l) (remove_list r (cdr l))))) ) ; sort the moves in "vals" list based on their move length values ; and then strips out their "length values ; ; i.e., if "vals" is ((3 (2 3)) (2 (1 2)) (5 (3 4)) (1 (2 1)) (2 (2 2))) ;then mrv_sort returns: ; ((2 1) (1 2) (2 2) (2 3) (3 4) ) ;function mrv_sort( ; ((num (num num)) (num (num num)) ):vals) : ; ((num num) (num num) ) (defun mrv_sort (vals) (cond ; base case, return the last move in "vals" ((null (cdr vals)) (cdr (car vals))) (t (let ;else keep sorting, using min_val function ;v is the min val in "vals" ((v (min_val vals))) (append (cdr v) (mrv_sort (remove_list v vals)))))) ) ; recurse down the search tree, expand out the children for last ; visited spot ; ; m_row is number of rows in board ; m_col is number of cols in board ; ; function recurse_down(number:m_row number:m_col):t/nil (defun recurse_down (m_row m_col) ; get the valid values, store as val (let ((vals (min_remaining_val m_row m_col))) (cond ; no valid values, backtrack ; note, that we test for sucessful completion before this ((null vals) nil) ; else recurse across (t (recurse_across vals m_row m_col)))) ) ; this function is exactly the same as recurse_across except ; that it calls recurse_down instead of recurse_down ; ;vals is valid moves, having the form: ; ((number number) (num num) etc.) ; m_row is number of rows in board ; m_col is number of cols in board ; ; function recurse_across( ; ((num num) (num num) ):vals ; number:m_row ; number:m_col) : t/nil (defun recurse_across (vals m_row m_col) (cond ; no more valid moves, backtrack ((null vals) nil) (t (cond ; if number of steps taken equals number of squares on board ; then we're done ((equal (+ steps 1) (* m_row m_col)) ; increment number of steps, add new visited square (setq steps (+ steps 1)) (setq visited-list (append visited-list (list (car vals)))) ; return t t) (t ; else continue moving until end ; increment steps and add to visited-list (setq steps (+ steps 1)) (setq visited-list (append visited-list (list (car vals)))) (cond ; recurse down, return t if recurse_down found solution ((recurse_down m_row m_col) t) (t ; if recurse_down did not find solution, backtrack, removing ; moves from visited-list and from "steps" as we backtrack ; and then recurse_across (setq steps (- steps 1)) (setq visited-list (reverse (cdr (reverse visited-list)))) (recurse_across (cdr vals) m_row m_col))))))) ) ;find the knights tour given board size of (m_row m_col) and ;starting position (row col) ;use herustics ; ;function find-knights-tour(number:m_row number:m_col number:row number:col) : ; ((number number) (number number) ) (defun find-knights-tour (m_row m_col row col) ; set the global variables (setq visited-list (list (list row col))) (setq steps 1) ; start searching... (cond ((recurse_down m_row m_col) visited-list) (t nil)) )
Failing Like Never Before
When I created this blog, I gave it the sub-heading "failing like never before," although at the time I had no idea how apt the name would become. You see, I recently come to realize while reflecting on my life, that my intellectual capacity and mental abilities peaked at around the beginning of eighth grade, and that since then I've been on a steady and slow decline. Every day of my life is, in short, more of a failure then the day that preceded it.Therefore, I am indeed failing like never before.
My grades in college have been lackluster and far from impressive, my transcript is peppered with Cs and there is a noticeable dearth of strong achievements on my resume. Once upon a time, a long time ago, I was a bright and attentive student who was always "on top of the ball." But now I have trouble focusing in class and cannot seem to bring myself to care as much about studying as I once did.
So my university has a policy that students in the school of engineering cannot drop a class after the Friday of the fourth week of the quarter. But a few weeks ago, just a day after the drop deadline for classes had passed, I suddenly realized that I was in some pretty deep trouble. As a result of my procrastination and difficulties in focusing on studying, I was severely behind in my circuits class and my midterm was just a few days away. Meanwhile, I still had a lot of work to do on my A.I. homework. Long story short, I couldn't drop my circuits class so I ended up flunking the midterm (although I did finish my A.I. homework and did a pretty good job on it). No matter how badly I've ever done a test in high school or college, I've never failed a test before, at least up until now. I was so depressed, that after the midterm, instead of riding my bike home I ended up riding for over an hour in a straight line away from campus; I think a part of me just wanted to run away from my problems.
There was a time when I could have banged out a seven page paper in a few hours, assuming that I knew enough about the subject matter. But a few weeks ago, I ended up staying up until four in the morning writing a seven page paper on air pollution. FOUR IN THE MORNING!!! And it wasn't even a well written paper at that. The worst part, was that I then proceeded to sleep through my class (which was from 9-12) and ended up turning my paper in late. When I was in high school, I woke up at 6:30 sharp everyday, regardless of what time I had gone to sleep or what day of the week it was. And up until this year of college, I had never turned in a late paper.
More on the failures of my life to come later...

