Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - harold

Pages: 1 ... 8 9 [10] 11 12 ... 16
136
Miscellaneous / Re: Creating my own linguistic language
« on: April 03, 2013, 02:57:57 pm »
What language(s) (if any) is it influenced by?

As for the number system, I .. don't really know. Personally I've long been an advocate of base 16 because of its simple connection with base 2, which makes it trivial to calculate with it [you only need algorithms for the basic operators, no tables], but as for the notation.. I don't really know. I have a couple of ideas that I think are bad which might somehow still be of value (you never know?):
- Residue Number System. I wouldn't call it intuitive, but you get to break up operations in lots of small pieces and is efficient in the sense that you end up writing down mostly small numbers (on the other hand you'd have a whole array of them, so that doesn't do that much good). It also allows trivial GCD and LCM, which is elegant IMO. But: division is terrible and you'd always be wondering how many moduli to use (and which).
- Continued Fractions. Not intuitive either. Doesn't solve the problem of how to write large numbers - you'd still end up with long base 16 strings. Harder for simple calculations. But it does let you write down crazy numbers efficiently and so some mathematical concepts could become easier to grasp, maybe.. such as fractions and square roots. I could see a mathematically super-advanced race using it all the time, but mostly because they'd be the "crazy mathematician" kind of guys, and I'm not sure what you're aiming for here.
- Base -16. Not too interesting. Doesn't help at all. But it's .. something?

137
  • Simulated Annealing is a nice trick that works very well for how simple it is (in it's basic form - it gets complicated when you make it fancy). It combines well with other tricks, since it's really more of a "framework-type algorithm" and not really a "mathy algorithm", so there are lots of "blanks" that you get to fill in. It's also attractive because it becomes arbitrarily good just by throwing more time at it - which means that on one side, you can make it quick if you don't really care that much about how good the answer is, or on the other side, you can make a very good answer just by waiting a long time. And it's the same code for both, so you can even make the speed a user input. That's a rare thing in algorithms.
  • A* is a very often a good way to speed up an exhaustive search. It's like BFS, but instead of a queue it uses a priority queue, sorted by "distance from root + estimated distance to goal". What makes it particularly useful is that it's guaranteed to find the optimal answer when the estimated distance to the goal is never higher than the actual distance (heuristics satisfying this condition are called "admissible"). The maximum over a bunch of admissible heuristics is still admissible, so you can often make the search faster by making up more heuristics (unless evaluating the heuristics takes too much time, of course). If your heuristic is accidentally not admissible, that's one of the worst bugs to diagnose, so be careful.
    [I thought about putting A* in the list when I created the thread but had thought that too many people would already know it, but maybe not everyone does so here it is]

138
Computer Projects and Ideas / Continued Fraction Math
« on: March 19, 2013, 09:57:52 am »
(Infinite) continued fractions (CFs) are a nice trick to store and manipulate numbers in a computer that would otherwise be hard to handle (such as irrationals and transcendentals). The nice thing about them, is that you can get a correct finite prefix of the sum/product/decimal-expansion/etc of a/two CFs using only finite* prefixes of (both) operand(s). That means that, as long as you ask for only finitely many digits of the result, a prefix of the actual correct result rolls out in finite time.

* but not always. For example, it's impossible to compare two equal infinite CFs - maybe the next term will make them differ, so you have to evaluate infinity terms. This also arises in "implicit comparisons" such as subtracting two equal infinite CFs or squaring a square root of an integer that isn't a perfect square. The CF library I've been working on tries to detect those cases, but it can get confused - it's better to just avoid those cases.

So, how do you do math with them? Didn't we all learn in school that you can't really do math with CFs in a mechanical way (ie you had to reason about it to come up with an answer)? Turns out there is a way, but I guess it's rarely taught. It's a shame, it's not really all that complicated and it's a nice trick to know.

Now, on to the library I've been working on. It's not "ready", and probably full of bugs (if you find one, please let me know), but it's "ready enough" to show some neat things that you might have thought were terribly hard to do, such as evaluating ##\frac{\pi e}{\sqrt{2}}## to 500 decimals. The example program is doing just that, and you can use Mathematica/wolfram-alpha to see it's correct. Just for fun it also tries to merge successive operations, because "one operation" is really of the form ##\frac{axy+bx+cy+d}{exy+fx+gy+h}## where x and y are the inputs, a through h are set to constants that determine the operation, so a lot of stuff can be put together in one operation, such as ##\frac{x}{y} + \frac{x}{2} + 3 = \frac{xy + 2x + 6y}{2y}##, merging 4 operations into 1.

I'm not sure if this has a real use, but maybe some of the people working on custom CASes are interested in the algorithm? The paper I linked to isn't one of the easiest papers to read, but I can explain it if anyone's interested in implementing it themselves. The limitations I mentioned would be kind of bad for a CAS, but you can hack around them by using a "maximum expansion depth". I didn't implement that because I'm still looking for a better solution.

139
Very good, Binary Indexed Trees are awesome, simple but powerful :)

Here's some more stuff I find interesting:
  • Bloom Filters. I haven't really used them yet, but they look very useful when you want to do a quick but inaccurate test so you can save a large portion of slower but accurate tests - for example, google uses them in Chrome to pre-test a list of "dangerous" domains locally, so most queries don't have to go all the way to their servers.
  • The Hungarian Algorithm finds a "best assignment" of "tasks" to "actors". This is an important optimization for real life, as well as in many programs, including games (for example if you have a bunch of units and a bunch of tasks in an RTS, and you'd like to not just pick the nearest the unit for each tasks greedily but calculate the optimal way to assign the tasks). It looks simple, but sadly it has steps that are difficult to do nicely on a computer.
  • Interpolation Search is an adaptation of Binary Search that works extremely well when the items in the list are roughly uniformly distributed in their keyspace. Often neglected because it's not as "theoretically pretty" as basic Binary Search, but frequently a win in practice.

140
  • Unrolled Linked List. Despite theoretical advantages, linked lists almost always turn out to be very disappointing compared to ArrayLists. Unrolled linked lists fix that to a certain degree - sometimes they may even beat ArrayLists.
  • Table Based Huffman Decoding. The most well-known way (frequently given in textbooks, because it's The Obvious Way) is going down the huffman tree bit-by-bit until you reach a leaf. The table based method in the simplest way makes a single table lookup to decode a symbol. With this trick, the performance of Huffman decoding increases from "unacceptable" to "very good". Note that it requires canonical Huffman codes - which most compression formats use, so it's widely applicable.
  • K-d trees and variants, useful for various geometry problems. For example, I used them to fit textures varying in size widely together onto a texture atlas. That isn't optimal, but a lot better than a naive approach and a lot faster than an optimal approach (it runs every time when the game starts, and does not significantly increase the loading time).
  • Fermat Factorization, an other trick for when trial division is too slow. It has different performance characteristics than Pollard's Rho: Rho is very good for small factors, Fermat Factorization is good for big factors.
Come on guys, post some more :)

141
I'll start out with some stuff I actually use and may not be widely known: ("widely known" is stuff such as red-black trees, array-based heaps, circular buffers, hash tables, linked lists, you name it - first year CS material)
  • Binary Decision Diagram solves all sorts of problems that you thought were hard or impossible, such as: boolean function equivalence, boolean satisfiability (and in fact the number of solutions, in time independent on the result) and Linear Boolean Programming. I've used BDDs with great success in many Project Euler problems (usually the "count solutions" part of BDDs) that were designed to require some mathematical insight. Great for "brute force - but smart".
  • Zero Suppressed BDD's - a variation of BDDs especially suited to sparse functions, such as when solving some Exact Cover (or regular Set Cover) problems (not when choosing a set has very non-local results, such as with Sudoku) and you can actually get a count of solutions, pick a uniformly distributed random solution or a solution that optimizes the sum of weights of the chosen sets. Also good for representing all Hamiltonian paths though a graph, which you can use to solve some nontrivial instances or the Traveling Salesperson Problem.
  • Dynamic Programming. Not an algorithm, but a class of algorithms so big that you have already used DP even if you didn't know it. For example, you know how to calculate Fibanacci numbers in linear time? That's DP. You've used Dijkstra's algorithm? DP. Learn about DP, it will come in handy. Maybe this shouldn't be on the list - almost everyone has heard about it.
  • Branch and Bound. The wiki entry is just a stub, so no link. The idea is simple enough, but powerful: you do a Depth First Search, but you stop going down the recursion tree when the solution can not possibly become better by going down this sub-tree than the best solution found so far. Especially good when combined with a fast approximation. This technique can save your ass when it looks like you are going to have to use actual brute force, but when the cost function is monotonic while going down a sub-tree. Often applicable to solving puzzle games. It may seen niche, but I've had to use this in real life software that is actually used by people.
  • Suffix Arrays, takes less space than a suffix tree, and useful for many of the same problems, such as many string problems (such as searching for substrings in sub-linear time). Other significant applications include a linear time Burrows–Wheeler transform (useful for data compression) and linear time Lempel Ziv decomposition (probably useful for LZ77/Deflate).
  • Miller-Rabin primality test for when trial division gets too slow. It will test 64bit numbers for primality in mere miliseconds.
  • Pollard's Rho algorithm for when trial division gets too slow and you actually need a factor, not just a boolean "IsPrime".
Let's get this going, I'm sure we can all learn something new and interesting from this thread if people start adding stuff to it.

142
News / Re: TI bans community calculator emulation
« on: February 22, 2013, 06:02:01 am »
Does this apply to the OS obtained when buying a calculator as well, or only to an OS downloaded from TI's site?

143
Math and Science / Re: A little theory I've gotten
« on: February 21, 2013, 12:30:02 pm »
Is that multiple time dimensions as in: "3+2 spacetime"?

That would put our universe in the "green area":

There is, afaik, no indication that we're actually there

144
ASM / Re: Learning z80 ASM
« on: February 21, 2013, 09:15:25 am »

145
Miscellaneous / Re: High level languages are vexing
« on: February 19, 2013, 07:21:43 pm »
Exactly. I don't fully understand how you'd want high level languages improved. Full low-level access? Or implementations of everything you could do with those low-level things in the standard library? You'd still find missing things.
A bunch of the ones that are take the most effort to implement. Just because it won't be complete doesn't mean it can't be better.

You need that modular multiplication to implement Miller Rabin. Do you want to argue that C# is not well suited to testing whether a number is prime? It's not some scripting language.. you're supposed to be able to do real things with it.

But anyway none of this is really to the point. The point is, it's vexing.

Also, this is derailing completely.

146
Miscellaneous / Re: High level languages are vexing
« on: February 19, 2013, 04:46:26 pm »
Also I think to debate languages everyone should put their ASM fanboyism/elitism stuff away (or any other language for that matter). Because someone loves a programming language or is experienced with it doesn't mean that language is flawless/superior in every way possible nor that it's factually easier/harder to use.
Harsh :)

You know I never said that, right.

I like C#, I think it's a nice language with a clean syntax and I work with it much more than I work with assembly, it (and it's not alone in this) just has this problem that some things are made harder than they should be, even though it would have been trivial to fix many of the problems in a way that in no way compromises the language. And I gave specific examples of cases that are particularly vexing. No generalizations.

147
Miscellaneous / Re: High level languages are vexing
« on: February 19, 2013, 10:03:28 am »
I would agree, but all the problems I named are easily solvable by just providing the relevant functions in the standard library. That doesn't make the language any harder to learn.

148
Miscellaneous / Re: High level languages are vexing
« on: February 19, 2013, 09:43:18 am »
No offense, but I think some of you are not getting the point: the things I listed are harder to do in high level languages (not just less efficient), which is completely the opposite of the idea behind those languages - they're supposed to make things easier than if you were working in assembly.
You either need some hack like inline asm or compiler-specific intrinsics (that is still harder than it would have been, or at the very least not easier), or you can't even use either (C#? Java - to a point. at least it has some interesting stuff in the Integer class).

149
Miscellaneous / Re: High level languages are vexing
« on: February 18, 2013, 01:07:51 pm »
Yes, but the examples I gave are not only slower in high level languages, they're harder to do. And that's just, well, contrary to the purpose of those languages.

150
Miscellaneous / High level languages are vexing
« on: February 18, 2013, 11:27:44 am »
High level languages make many things harder instead of easier, I'm sure most assembly programmers feel the same way, especially when I show you what I mean.

So you want the full result of a multiplication. That's non-trivial on z80, but on x86 (and many others) you can get this in one or two instructions.
But now you're working in a high level language again and guess what, it won't let you do that. You could perhaps use a type that is twice as wide.. unless it was the widest type already. So you have to split your numbers and multiply the parts separately. To make matters worse, your compiler isn't detecting the idiom, and what should have taken 5 cycles or so now takes more than a dozen. Wow.

Ok but at least that was solvable and the performance may be acceptable. But now you want to do a 64bit modular multiplication. What's the problem, just mul\div, right? (assuming the inputs were already reduced). But of course that relies on 1) a full multiplication and 2) a full division. Not gonna happen. So now what, do a multi-word division? You can.. but it's complex and slow and bug prone, and it's something that's supposed to take 2 instructions.

Non-standard extensions to C/C++ solve this, but what if you're working in C# or Java? There are, afaik, no good solutions. (no, using bigint isn't a good solution, if anything it's worse)

Let's add some more, there's a ton of stuff like this.

Say you want to take the average of two unsigned numbers. Easy, right? Just add them and rotate-right-with-carry by 1.
Oh wait, you don't have a carry, because this is a high level language. Solutions range from "absolutely horrible" to "wrong", except perhaps for "average = low + ((high - low) / 2)" which I suppose is just about acceptable.. but I still have this nagging feeling of "but it should be simpler!". I suppose a smart compiler can detect this idiom and do the right thing anyway, but it's vexing.

Or do a multi-word addition/shift. There are various ways to calculate the carry, but you're still forced to jump through hoops just because there's no "add/shift with carry".

Or, you want to find the index of the lowest/highest set bit. Simple. Even in Java, though I wouldn't trust it to compile to the right thing. But in C#? Nope. You'll have to write something complicated and/or slow to emulate it.

Rotates. Ok there is "(x << n) | (x >> -n)" and the likes of it, and then hope&pray the compiler isn't an idiot (C and C++ compilers generally aren't idiots with this, but once again C# loses). It could have been so simple. Say, >>> and <<< operators. Though of course Java already used >>> because it doesn't have unsigned types (worthy of a whole separate rant, especially the fact that bytes are signed). Do you even need rotates? Yes. You do.

Pages: 1 ... 8 9 [10] 11 12 ... 16