Friday, October 15, 2010

 

Thoughts about (object) cloning

One commonly-useful method for objects to support is cloning. Unfortunately, cloning tends to pose many difficulties in object-oriented languages, since the type of object returned by the clone method will vary depending upon the type of object performing it, and since base types may be used to derive some types that allow cloning and some that do not.

As I see it, there are four types of classes when it comes to cloning:
  1. Those that simply cannot be cloned
  2. Those that are perfectly happy if MemberwiseClone'd, but don't promise that their descendant classes will support cloning.
  3. Those that can be meaningfully cloned, but they require more than MemberwiseClone, and they don't promise that their descendants will support cloning.
  4. Those that can be cloned, and promise such ability on behalf of themselves and any descendant classes.

Unfortunately, the .net framework really doesn't do much to indicate which types fall in which category. My proposed pattern would make things much clearer, and would look something like this:

Class SampleSemicloneableBase
Enum DontTryThis
NoReallyDont = 0
End Enum

Public SampleArray1(0) As Integer

Protected Overridable Function CloneBase() As Object
Dim Result As SampleSemicloneableBase
Result = CType(MyBase.MemberwiseClone(), SampleSemicloneableBase)
Result.SampleArray1 = Result.SampleArray1.Clone
Return Result
End Function

Protected Shadows WriteOnly Property MemberwiseClone As DontTryThis
Set(ByVal value As DontTryThis)
Throw New NotSupportedException()
End Set
End Property
End Class

Class CloneableDerived
Inherits SampleSemicloneableBase
Public SampleArray2(0) As Integer

Public Shadows Function Clone() As CloneableDerived
Return CType(Me.CloneBase, CloneableDerived)
End Function

Protected Overrides Function CloneBase() As Object
Dim Result As CloneableDerived
Result = CType(MyBase.CloneBase(), CloneableDerived)
Result.SampleArray2 = Result.SampleArray2.Clone
Return Result
End Function

Public Overrides Function ToString() As String
Return SampleArray1(0).ToString & "." & SampleArray2(0).ToString
End Function
End Class

Class NonCloneableDerived
Inherits SampleSemicloneableBase
Protected Shadows WriteOnly Property CloneBase As DontTryThis
Set(ByVal value As DontTryThis)
Throw New NotSupportedException()
End Set
End Property
End Class

Class cloningTest
Shared Sub test()
Dim thing1 As New CloneableDerived
thing1.SampleArray1(0) = 1
thing1.SampleArray2(0) = 2
Dim thing2 As CloneableDerived = thing1.Clone
Debug.Print(thing1.ToString & "/" & thing2.ToString)
thing2.SampleArray1(0) = 3
thing2.SampleArray2(0) = 4
Debug.Print(thing1.ToString & "/" & thing2.ToString)
End Sub
End Class

For this example, the base class has one field which needs to be cloned, and the cloneable derived class adds another. Each cloneable derived class should declare a "Public Shadows Function Clone()" of its own type, which should call the overridable "CloneBase()" and typecast the result as appropriate. Each cloneable class which needs to do anything when cloned other than call its parent's cloning method should add an override to CloneBase, and that override should start by calling it's parent's CloneBase method.

Classes which aren't going to support cloning-related methods of their parents (e.g. MemberwiseClone in the case of SampleSemicloneableBase, or CloneBase in the case of NonCloneableDerived) should seal off those methods from protected classes; the implementation here is perhaps a little cutesy, but should be pretty good (Intellisense should set people straight if they try it).

Classes which follow my pattern can be readily classified into types #1, #3, and #4. Type #2 is a bit dodgy; classes which follow my pattern would not be type #2 (they'd be #3 even if all they do is call Object.MemberwiseClone) but there's no way of knowing whether a type which supports MemberwiseClone really supports it, or simply hasn't disabled it. But for types which follow the pattern, the cloning status would be readily apparent.

Monday, January 12, 2009

 

X08 banking specification

The X08 banking system is a new method of banking which nominally allows 32K of ROM and 8K of RAM. Because the cartridge must contain an operating system in addition to the user code, not all of the ROM and RAM will be available.

From a hardware standpoint, ROM is stored at addresses $00000000-$00007FFF and RAM is stored from $40000000-$400001FFF. As noted above, the first part of RAM and ROM will be used by the operating system. The emulator wouldn't have to worry about the OS RAM and ROM requirements, though it may be helpful to provide a 'trap' if a RAM address is written illegally. I'm not sure the best way to indicate what RAM areas should be considered legal and illegal, though.

Because the X08 controller is microprocessor based, it allows some features in addition to its rather generous RAM allocation. Most notably:
  1. It allows the 6502 address space to be subdivided into four 1K zones which can be moved on byte boundaries anywhere within RAM or ROM address space.
  2. It provides high-speed block copy operations; future versions of the specification may allow other special operatons as well. The cartridge will clock out NOPs while such an operation is in progress, and then clock out a JMP to the instruction following the instruction that triggered it; thus, while such an operation will take time, the user need not worry about waiting for it to complete.

The X08 banking specification is in some regards trickier than others, because the main controller is itself another microcontroller which can be in a number of different states at the start of each memory cycle. Much of this will usually be transparent to the person writing code for it, but to minimize the likelihood that code will work beautifully in emulation and then fail in weird and bizarre ways on actual hardware, an emulator should try to mimic these behaviors as closely as possible.

The following is a list of cartridge states. Note that at the end of each cycle, the cartridge may be outputting a byte of data or may be floating the bus. If the processor attempts a read while the bus is floating, the data bus contents should be randomized (on real hardware they may be unpredictable). If the processor attempts a write while the bus is being driven, that should probably cause a fatal error except in "inject" state. Note also that except when the processor is in busy state, any bus cycle which uses the same data as the previous one will be ignored.

Normal State
This is the most common state of the system. Each address is categorized into a 1K block, and then processed appropriately. A more detailed description appears below. This state may progress into many of the other states, based upon the address accessed.
Simple-Fetch State
If an access is not in cartridge space, it will be ignored. Otherwise the system will assume that the address is a normal read with the same memory-bank offset as the previous read. This has two main consequences:
  1. The first byte of the instruction which follows a bank switch will be fetched from the page that was selected before the bank switch occurred.
  2. If an instruction which triggers a bank-switch appears as the last byte of a bank, the first byte of the following instruction will be accessed from the byte following the end of the bank from which the instruction had been fetched. If the banks point to consecutive regions of memory, this will be as expected. If not, it may cause weird behavior.

In any case, the system will revert to Normal State following a Simple-Fetch access.
Simple-fetch-and-handle-write State
Because certain write operation trigger actions which cannot be undone by simply writing new data, the system will latch the address and data bus on each cycle until it sees a change in the address bus other than at bits 8 and 9. The system will then process a simple read, and then process the write. Note that indexed writes may safely cross page boundaries, but not bank boundaries. This state reverts to Normal State.
Enter-Busy-State State
The system will wait for a change in the address bus other than at bits 8-9, and then examine bit 12. If bit 12 is set, the system will drive $EA (NOP) onto the bus and queue up $4Cxxxx for injection state (where xxxx is the fetched address). The system will then perform a function based upon the previous access (said function will probably set busy_cycles, since the purpose of this state is to handle operations that will take multiple 6507 cycles to complete).
Busy State
The cartridge will keep floating the bus or driving it with a constant value until a specified number of cycles have elapsed. This state takes priority over all others, and it is recommended that an emulator use a "busy_cycles" counter; if it's non-zero, decrement the counter and perhaps check for bus contention (an attempted write while the cartridge is driving the bus) but otherwise do nothing. Busy State may progress to either Normal State or Injection State.
Injection State
Each time the address bus changes and the new address is in cartridge space, output a byte from the "injection queue". The injection queue allows up to four bytes to be loaded provided the last is not zero. The suggested implementation is to store all the bytes in a 32-bit unsigned integer. After each address change, if the address is in cartridge space, output the least significant byte and shift the integer 8 bits to the right. Once all data are shifted, the system will progress to Normal State.

As noted above, the system address space is divided into eight 1K blocks. The functions of each block are as follows:
ADDRESSFunction
$0000-$03FFSome key registers at $007x, $02xx, and $03xx, as described below.
$0400-$07FFOne page for each bank--Select mode for a bank based upon LSB of address
$0800-$0BFFOne page for each bank--Add LSB of address to bank pointer
$0C00-$0FFFOne page for each bank--Subtract LSB of address from bank pointer
$1000-$13FFUser Bank 0
$1000-$13FFuser Bank 1
$1000-$13FFUser Bank 2
$1000-$13FFUser Bank 3

Each of the three User Banks may be independently programmed to use any of the following modes:

RAM/ROM read
Read a specified address from RAM or ROM, in typical ordinary fashion
RAM write
Writes a specified address to RAM. Note that indexed writes are acceptable, even if they cross page boundaries within a bank. Reads will return arbitrary data, and a read which is followed by any address other than a page wrap will "accidentally" store arbitrary data. RAM writes will use the Simple-Fetch-and-Handle-Write state.
Tethered read
Like a normal read, except that the base address of bank 0 is added to the address for the current bank.
Tethered write
Like a normal write, except that the base address of bank 0 is added to the address for the current bank.
Set Function Pointer
Performs a RAM/ROM read, but also sets the 'Function Pointer' to the address accessed (in RAM or ROM).
Byte Copy
Storing a byte to a bank in Byte Copy mode will perform a block copy from the Function Pointer to the destination address. The number of bytes copied will be the value stored, plus one. This will use the Enter-Busy-State state; the system will be busy for approximately 2+(bytes/8) cycles. Reading a byte in a copy-mode bank may cause unpredictable behavior.
Word Copy
Word Copy mode is similar to Byte Copy mode, except that (1) the specified value is the number of 16-bit words to copy, minus one (instead of bytes), and (2) both source and destination addresses must be even. Words are copied at the same loop rate as bytes (so 2+(words/8) cycles).
Longword Copy
Longword Copy mode is similar to Byte Copy mode, except that (1) the specified value is the number of 32-bit longwords to copy, minus one (instead of bytes), and (2) both source and destination addresses must be multiples of four. Words are copied at the same loop rate as bytes (so 2+(longwords/8) cycles).
Indirect Read
A byte is read from RAM at the specified address, and the upper 7 bits are used to select an entry in a table of 128 16-bit addresses pointed to by the Function Pointer. The value at that address in RAM is then fetched and given to the 6507. If the original byte read was odd, the address in the table will be incremented. Code may be executed from a bank in this mode (indeed, that's the whole purpose!) provided that it does not perform any writes to the cartridge nor perform any bank switches.

Key bank-switch addresses:

Note that any access to a bank-switch address will cause the following cart-space address to be performed in Simple-Fetch state.

Tuesday, January 06, 2009

 

Silly poker odds trivia

A few interesting (though not terribly useful) observations about poker odds; I believe these are correct, though I might have missed something.

  1. A player holding pocket aces always has the best of it pre-flop when playing against three opponents, no matter what the opponents hold. Against four opponents, it's possible for the player not to have the best of it, but he can't be a very big dog (I think the worst-case is AcAd vs AhAs KcKd Tc9c 7d6d, with all the non-ace opponents holding the player's suits; that yields a pot equity of over 18.118%). If there are opponents who fold pre-flop, the cards they render dead may shift the odds. If there are six people in a hand to start, two of whom have pocket aces, and three of the players fold pre-flop, it's possible for the player who doesn't have pocket aces to be the only one to have over 33.3% pot equity.

  2. A player holding pocket aces could theoretically be almost totally dominated (less than 0.8% pot equity) when playing against nine opponents, but I believe there are only one arrangement of cards (given player's suits) which would push pot equity below 1%. If player holds AcAd, opponents hold AsAh and 6c6d-KcKd. The player has zero chance for an outright win, and less than 1.6% chance for a chop (most chops are 2-way). Changing any opponent's card adds many outs. For example, changing the 6's to 5's would allow 2345x (x > 6) as a winning out, with 126 suit combinations and 14 possibilities for x, in addition to adding some full-house outs. Without the change, the player's only chances for an out would be two-way chop with a four-of-a-kind 2-5 (remaining card anything) or else a hand with all cards in the range 2-5 (roughly 4,368 out of 201,376, though some of those double-count four-of-a-kinds or else lose outright), or a six-way chop with a straight flush (6-Q high in hearts or spades),

    It's interesting to note that even the opponent with the worst hand equity (the 7's) dominates the player by a factor of over 7.5 despite having six open overpairs; it's also interesting to note that the opponent with pocket aces has the best of it, with slightly over 10% hand equity.

  3. A player holding pocket kings against seven opponents could be drawing stone cold dead (e.g. against KK AA AA TT TT 55 55) but I don't know if there's any scenario with six opponents where the player wouldn't have any chance for even a chop. Note that the player would be drawing dead even if six of the opponents fold (any only the player with dominating aces stays in). The permutation of cards among those six players would be completely arbitrary.

  4. Against four opponents, pocket kings may have a hand equity well below 0.1%. Player holds KcKd; opponents hold AcAd, AhKh, AsKs, 8c7c. The player can win outright only with 9TJQx in clubs or diamonds (76/850,668 possible boards); the only other outs, for a five-way chop, are straight flushes (6-J high, in hearts, spades, or diamonds) or straights (8-J high, in suits that don't give opponents a flush).

Most of these observations should not be even remotely considered in actual play (it would be foolish to fold pocket aces on a ten-person table for fear that one might be totally dominated) but I find them all interesting from a mathematical perspective.

Friday, September 26, 2008

 

The crash is inevitable, necessary, and not to be feared

In examining the various plans to deal with the financial crisis, there seems to be a common element: a desire to avoid at all cost the collapse of an interlocked collection of derivative securities which could be called the House of CarDS (credit default swaps). The fear is that the massively tangled web of credit default swaps and other derivative securities will explode like a powderkeg that will destroy the economy if things go sour; because of this fear, the collapse must be prevented at all costs.

That attitude is fundamentally wrong and dangerous. First of all, it allows Americans to be held hostage to any demands financial institutions might make. Fail to do as they say, and they'll drop a match. Secondly, the costs of keeping the House of CarDS from collapsing are going to increase exponentially until it does collapse. Since the collapse is inevitable, it would be foolish to spend trillions of dollars postponing it. Thirdly, a collapse of the House of CarDS would not cause a major loss of value in the assets therein; since the loss has already occurred and has simply not been realized, the collapse would simply represent the acknowledgment of the already-existing loss. Fourthly, the biggest factor in today's credit lockup is that nobody knows what any of the paper assets are worth. If the paper assets in one's account are only worth $0.05 on the dollar, it's better to liquidate them and have $0.05 on the dollar of real assets, than to keep pretending the assets are worth face value when everyone knows they're probably worth less but nobody knows how much.

The first point should be self-explanatory. The second point is not so self-explanatory, but it is both observable empirically and explainable theoretically. I'll return to it later. As for the third third point, consider the following analogy: Joe Banker opens up a bank. Individual account holders are limited to depositing $100,000. The first $10,000,000 that people deposit in are shown on display. Any money that's put in after that goes to the vault in the back. What Joe doesn't tell anyone is that he actually pockets 80% of deposits and send them to secret offshore accounts in Fredonia. Each individual account holders can see that the bank has over $10,000,000 in assets, which is clearly enough to pay him off. What the account holders don't see is that the same assets are being used to back many times their worth in deposits, so even though people have deposited a total of $1,000,000,000 in the bank, there are only about $210,000,000 worth of assets backing them up.

Would a run on the bank cause the people to lose money? Not really. A run on the bank would cause the later depositors to lose everything, but the major loss came when Joe pocketed 80% of the deposits and sent them off to Fredonia. While a bank run would arbitrarily redistribute the losses (so those who withdraw early pass their losses off to latecomers), depositors on average will have lost $0.79 on the dollar before the run even started. The only effect of the run will be a fight over the last $0.21.

Returning to the original second point (exponential cost to prop things up), assume that Joe's Bank hasn't crashed yet, but the reserves are getting low (people who deposit money sometimes have the audacity to withdraw it). So Joe decides he needs to get more depositors. Easy solution: offer higher interest rates. In response to the higher rates, more people deposit the money, and Joe keeps getting more and more money to put in his pocket. Each dollar that Joe takes in and then pays out must be replaced by more than $1. Even if Joe weren't pocketing anything, the payment of interest would require an increase in the rate of deposits. If Joe starts pocketing money for himself as well, that will cause things to escalate rapidly.

On to point number four. Suppose that Acme Plastics has recently borrowed a lot of money to purchase another company which, as it happens, had lots of assets of dubious worth. If those assets are worth $0.10 on the dollar, Acme Plastics is solvent. If they're worth less, it's not. Acme Plastics has an assembly line all set up to produce Tickle Me Paulson dolls, and stores are waiting to receive them. All Mr. Acme has to do is get $100,000 of raw plastic on credit and he'll soon have $1,000,000 worth of merchandise. Unfortunately, since potential creditors have no way of knowing whether Acme Plastics is solvent, they have little desire to lend money and risk having to fight other creditors for its return.

If the crash of the House of CarDS revealed the real value of Mr. Acme's dubious assets to be $0.15 on the dollar, the crash would help Acme Plastics get credit, since he could show that his business was solvent. Even if it showed the value of those dubious assets to be only $0.01 on the dollar, though, it could still be a good thing for the Acme Factory. Markets love gains, but they tolerate losses. What they don't like is question marks. If the assets are shown to be worth $0.01 on the dollar, and that is insufficient to meet obligations to existing creditors, there are many ways to keep the factory open. Creditors may accept a debt-for-equity exchange. Or the business could be liquidated with the factory, intact, bought out by someone who could then supply the raw plastics needed to begin production. Even if none of those desirable things happened and Acme Plastics was disbanded, that wouldn't be much worse than having the company go broke because it couldn't get the credit needed to produce products.

So what do all these points mean? The fundamental danger in today's marketplace is not that there will be a crash, but rather people will act irrationally in an effort to avoid one. Nobody is going to want to see his portfolio drop by $0.50 on the dollar overnight, but throwing in good money after bad in an effort to deny reality is no solution. A lot of the money put into the markets by investors is gone. No amount of hope or optimism will change that. The only way to restore confidence in the markets is to find how much money is gone and how much remains, and then move forward.

Saturday, July 26, 2008

 

The Jellybean Counter

Suppose a town decides to have a contest for people to guess the numbers of jellybeans in various jars. To produce an official count, they appoint an official Jellybean Counter. His job is to determine what the whole number of jellybeans in each jar is.

The first jar contains 427 perfect jellybeans and nothing else. The Jellybean Counter's job is easy. His job is to report the number 427. His job is not to report 426, or 428, or for that matter 5,591 or 57. His job is to report 427.

The second jar contains 503 perfect jellybeans, along with half a cherry jellybean and half a licorice jellybean. What's is the Counter supposed to do here? His job is not to produce a description of the jar's contents, but a whole number. If the rules don't say how half-jellybeans should count, what number should he report? He could do his job by reporting 503, 504, or 505. He would not be doing his job if he reported any larger or smaller number.

In the interest of fairness, the Jellybean Counter should try to make clear what rules he intends to follow in cases that are not addressed by official rules. He must also, however, not allow his own efforts at rulemaking to take priority over any official rules, nor over common sense. For any jar of beans, it will be obvious that any number of beans outside a certain range is just plain wrong. The Jellybean Counter might have formulated a wonderful rationale for a count value outside that range, but no matter how beautiful his logic, such a value would be wrong.

Today's courts are like an overly-creative Jellybean Counter. If they don't like the result that's mandated by the law and the case before them, they formulate some rationale to justify a different answer. Their usurpations are then used to justify further usurpations.

I wish some judges would be more willing to put their foot down on such dangerous nonsense. In ambiguous situations, it is often right and proper to rely upon precedent to select among alternative judgments. In such cases, however, the precedent isn't necessary to justify a judgment, but merely to explain why it was chosen in preference to other equally-justifiable judgments. If a judgment cannot be justified without reference to precedent, I would suggest that it is not legitimate. I can think of no exceptions.

Friday, November 02, 2007

 

Flash drives

Who came up with the idea of making flash drives emulate sector-based disks? Blah.

Saturday, August 04, 2007

 

Back to the Classics

Well, I got out my Commodore 128 and VIC-20. The left shift key on the C-128 doesn't seem to work, which is disappointing. I think I've had that problem before, though, and solved it by swapping around the squishy things among different keys. Since there are some keys I never use (e.g. "Line feed") I could borrow the squishy things from those.

Tuesday, May 01, 2007

 

Run Fred Run!

Fred Thompson seems likely to run. I don't know everything I'd like to know about him, but the only negative I'm aware of is that he once supported Campaign Finance Reform. Since he has since recanted on that, and I believe in forgiving repentant sinners, I don't particularly hold that against him. Otherwise he seems way better than Rudy Giuliani or John McCain, and at this point I trust him more than Mitt Romney.

I think perhaps he doesn't want the presidency for himself as much as the other candidates; other people may see that as a bad thing, but I see it as a good one. If he runs, it will be because he wants the country to have a good President. I think he'd probably be happier if the country had a good President that wasn't him, but I doubt he thinks that's possible.

Thursday, March 22, 2007

 

Are there no good Republican candidates?

It's discouraging, being more than 18 months away from an election and knowing it's almost certainly going to be a disaster. Maybe Mitt Romney will win, and maybe he'll turn out to be a good candidate, but I'm not holding my breath.

Winning as a Republican requires articulating a vision. Unfortunately, most "Republicans" seem to have no real vision. They're just Democrat lite--the least rational position of all.

Friday, January 05, 2007

 

Conservatives and capitalism

Many conservatives fail to acknowledge the various ways in which liberal policies may, superficially, "work". Liberals are in many cases behaving quite sensibly in deriding their "Ivory Tower" arguments, since they completely fail to acknowledge (and seemingly contradict) readily-observable phenomena.

One analogy I like to use is to imagine a store that comes changes management; the new manager decides that purchasing inventory is a waste of money, so for every ten units of merchandise he sells, he'll buy five to replace them. This allows him to cut prices by 25% while increasing his worker's wages by 50%. Who would have thought it possible to cut prices so much while still giving such a nice raise to employees?

Perhaps that example may seem over-simplistic, but many liberal policies operate on the same principle as that store. Conventional arguments against them would be akin to arguing that the store couldn't possibly raise wages without raising prices, nor cut prices without cutting wages.

A key to resolving many such conundrums is to consider capitalisation and policies' effects thereon. Consider the electricity industry. Generators cost money, and periodically need to be replaced. Left to its own devices, a power plant will make a significant nominal profit, but will from time to time spend a large chunk of that overhauling or replacing equipment. If the power plant is prevented from making such a profit, it may continue to operate at nominal profit as long as the equipment holds out, but then hit a snag. It won't have enough money on hand to buy the needed equipment, and it will be hard to attract people to invest much money without prospects for significant profit. The only way the plant will be able to stay in business will be to impose a very large rate increase (which must be large enough either to collect the money for a new generator fairly quickly, or else to reduce demand to the point that the generator that needed replacement is no longer required). Of course, the fact that customers had been receiving cheap electricity for so many years will only aplify their outrage when it ends. Of course, nobody will consider that the sudden rate increase became necessary because of the earlier lower prices.

This page is powered by Blogger. Isn't yours?