Oxbridge have never had to 'let in dumber people'. They are always heavily over-subscribed, and give offers to a small fraction of the people who come for an interview, let alone apply.
The whole point of the interview process is to assess not just the applicant's past achievements, but what they might be able to achieve if they got their place at the uni. Part of that is looking at the applicant's background, and knowing that even if they aren't currently at some elite high-fee school, they might still have the ability and capability to do well.
I am all in favor of this style of selection. The dark old days of "this kid's dad went to our college, we should do them a favour and let them in" are long gone, thankfully.
Can you point to any kind of evidence that Oxbridge are dumbing down their teaching, or lowering their standards of teaching? I doubt it.
Full disclosure: cambridge alumni, from a state school!
In addition, the colleges have a lot of data about the people they interview and how well they do during the degree programme.
My understanding (based on a discussion with one Natural Sciences admissions tutor at one Cambridge college nearly 20 years ago, so strictly speaking this may not be true in general, but I'd be surprised if it wasn't common) is that during the admissions process, including interviews, applicants are scored so they can be stack-ranked, and the top N given offers. Then, for the students that are accepted, and get the required exam results, the college also records their marks at each stage of their degree. To verify the admissions process is fair, these marks are compared with the original interview ranking, expecting that interview performance is (on average) correlated with later degree performance.
I don't know if they go further and build models to suggest the correct offer to give different students based on interview performance, educational background, and other factors, but it seems at least plausible that one could try that kind of thing, and have the data to prove that it was working.
Anyway my guess is that of the population of people who would do well if they got in, but don't, the majority are those whose background makes them believe it's "not for the likes of me", and so never apply, rather than people who went to private schools, applied, and didn't get a place.
(also a Cambridge alumni from a state school, FWIW),
All these Cambridge alumni with this dodgy Latin, 'smh'! You're an alumnus, or identifying as an alumna! (Identifying as many alumni at a stretch, but then still not 'a Cambridge alumni'.)
(alumnus not of Cambridge, but from a state school, fwiw)
On student evaluations, I wouldn't be surprised of Oxbridge do badly as so many pf the dons were at or near the top of their year at the university, weren't employed for their teaching abilities, and seemed unable to comprehend they were not teaching cohorts entirely full of clones of themselves.
Dumbed down it was not, in my experience. Dumbing down would be a way to up the score on these rankings, though.
And is this new generation doing paticularly well in solving our problems or advancing the nation over the previous one? I can't see much examples, I do remember going through some of the science projects shown in undergrad showcase but none of them were tackling key bottlenecks or doing something novel.
Improvement suggestion: Keep the search text in the search field when you show the results. The 'what are you looking for' box gets cleared when you show the results, it would be nicer if the search text was kept so that you could tweak it.
Thanks for the feedback. We're still working out the ideal way to manage the search, lots of trade-offs depending on what route you go. But there's definitely room for improvement.
Does that mean it excludes most of the results from "Floor to ceiling libraries without a ladder"?
You know, if I'm buying a house, I think I can supply my own ladder separately...
Less pedantically, what I'm trying to say is: are you really sure these are the kinds of searches that home buyers are really looking for? "Home in london, under £1m, with big beautiful windows" - I suspect that most London buyers are going to care an awful lot about where in London the house is, a city-wide search isn't going to be useful to most. Maybe your functionality (as presented) won't inspire actual buyers.
Speaking of which, that might be a way to improve it - combine with location & mapping data to figure out nearby transport, services, schools, etc...
For sure, those searches are more about showing what’s possible (and making browsing fun) than what a high-intent buyer would actually type in.
That said, from speaking to a lot of London buyers, people are often more flexible on location than you’d expect. The real criteria tend to look more like: “3-bed house under £700k, 30 min commute from [office], near a park, low crime, good schools” rather than “3-bed in Hackney.” Basically along the lines of the location / mapping data you're suggesting.
We’ve already built travel-time search and plan to layer in more of that other 'services' style data in the next few months.
But it is (or was originally) used in lots of places, not just jump tables, generally to do relative addressing, for example when you want to refer to data nearby, e.g.
Ah I miscommunicated, I still think PC can and should be used in places like the operand of an LDR / ADD. It's using it as the output of certain instructions (and allowing it to be used as such) that I take issue with. ARMv4T allowed you to set PC as the output of basically any instruction, allowing you to create cursed instructions like this lol:
Isn't writing to it except by a branch instruction undefined behaviour?
If you can use it as an operand, it has a register number, so you can use it as a result, unless you special-case one or the other, which ARM didn't do because it was supposed to be simple. They could have ignored it by omitting some write decode circuitry, but why?
It's not really UB, I've seen games do things like this before. Basically, all data processing instructions can now act as branch instructions, simply by having their dest be PC. Bowser's Inside Story on the DS for example liked to use EOR to write to PC, as a form of encrypting their pointers.
Yeah I think AARCH64 special cases it? Not too familiar with their encoding or how they achieved it. My guess as to why is that it allows you to use more helpful registers (e.g. a zero register) in data processing instructions.
I think I can see your point though - from the perspective of ARMv4T's design, which was to be a simple yet effective CPU, making the PC a GPR does its job. Nowadays the standards are different, but I can see why it made sense at the time.
Yeah, it was that way for all previous ARM processors too, for exactly that reason. Adding special cases would have increased the transistor count, for no great benefit.
The only downside was that it exposed internal details of the pipelining IIRC. In the ARM2, a read of the PC would give the current instruction's location + 8, rather than its actual location, because by the time the instruction 'took place' the PC had moved on. So if/when you change the pipelining for future processors, you either make older code break, or have to special case the current behaviour of returning +8.
Anyway, I don't like their reaction. What they mean is 'this decision makes writing an emulator more tricky' but the author decides that this makes the chip designers stupid. If the author's reaction to problems is 'the chip designers were stupid and wrong, I'll write a blog post insulting them' then the problem is with the author.
Hey, I'm the author, sorry it came off that way, I was really just poking fun. I should've definitely phrased that better!
But no, I really think that making the program counter a GPR isn't a good design decision - there's pretty good reasons why no modern arches do things that way anymore. I admittedly was originally in the same boat when I first heard of ARMv4T - I thought putting the PC as a GPR was quite clean, but I soon realized it just wastes instruction space, makes branch prediction slightly more complex, decrease the number of available registers (increasing register pressure), all while providing marginal benefit to the programmer
Anyway, I took the time to rewrite that paragraph a bit to be more respectful. :P Hopefully that'll come off better. The website take a few minutes to update.
The reason was because it makes subroutine return and stack frame cleanup simpler.
You know this, but background for anyone else:
ARM's subroutine calling convention places the return address in a register, LR (which is itself a general purpose register, numbered R14). To save memory cycles - ARM1 was designed to take advantage of page mode DRAM - the processor features store-multiple and load-multiple instructions, which have a 16-bit bitfield to indicate which registers to store or load, and can be set to increment or decrement before or after each register is stored or loaded.
The easy way to set up a stack frame (the way mandated by many calling conventions that need to unwind the stack) is to use the Store Multiple, Decrement Before instruction, STMDB. Say you need to preserve R8, R9, R10:
STMDB R8-R10, LR
At the end of the function you can clean up the stack and return in a single instruction, Load Multiple with Increment After:
LDMIA R8-R10, PC
This seemed like a good decision to a team producing their first ever processor, on a minimal budget, needing to fit into 25,000 transistors and to keep the thermal design power cool enough to use a plastic package, because a ceramic package would have blown their budget.
Branch prediction wasn't a consideration as it didn't have branch prediction, and register pressure wasn't likely a consideration for a team going from the 3-register 6502, where the registers are far from orthogonal.
Also, it doesn't waste instruction space: you already need 4 bits to encode 14 registers, and it means that you don't need a 'branch indirect' instruction (you just do MOV PC,Rn) nor 'return' (MOV PC,LR if there's no stack frame to restore).
There is a branch instruction, but only so that it can accommodate a 24-bit immediate (implicitly left-shifted by 2 bits so that it actually addresses a 26-bit range, which was enough for the original 26-bit address space). The MOV immediate instruction can only manage up to 12 bits (14 if doing a shift-left with the barrel shifter), so I can see why Branch was included.
Indeed, mentioning the original 26-bit address space: this was because the processor status flags and mode bits were also available to read or write through R15, along with the program counter. A return (e.g. MOV PC,LR) has an additional bit indicating whether to restore the flags and processor state, indicated by an S suffix. If you were returning from an interrupt it was necessary to write "MOVS PC, LR" to ensure that the processor mode and flags were restored.
# It was acceptable in the 80s', It was acceptable at the time... #
ARM1 didn't have a multiply instruction at all, but experimenting with the ARM Evaluation System (an expansion for the BBC Micro) revealed that multiplying in software was just too slow.
ARM2 added the multiply and multiply-accumulate instructions to the instruction set. The implementation just used the Booth recoding, performing the additions through the ALU, and took up to 16 cycles to execute. In other words it only performed one Booth chunk per clock cycle, with early exit if there was no more work to do. And as in your article, it used the carry flag as an additional bit.
I suspect the documentation says 'the carry is unreliable' because the carry behaviour could be different between the ARM2 implementation and ARM7TDMI, when given the same operands. Or indeed between implementations of ARMv4, because the fast multiplier was an optional component if I recall correctly. The 'M' in ARM7TDMI indicates the presence of the fast multiplier.
> Adding special cases would have increased the transistor count, for no great benefit.
No, it's exactly backwards: supporting PC as a GPR requires special circuitry, especially in original ARM where PC was not even fully a part of the register file. Stephen Furber in his "VLSI RISC Architecture and Organization" describes in section 4.1 "Instruction Set and Datapath Definition" that quite a lot of additional activity happens when PC is involved (which may affect the instruction timings and require additional memory cycles).
Is this really C++ specific though? It seems like the optimisations are happening on a lower level, and so would 'infect' other languages too.
Whatever the language, at some point in performance tweaking you will end up having to look at the assembly produced by your compiler, and discovering all kinds of surprises.
LLVM isn't perfect, but the problem here is that there's a C++ compiler flag (-ffast-math) which says OK, disregard how arithmetic actually works, we're going to promise across the entire codebase that we don't actually care and that's fine.
This is nonsense, but it's really common, distressingly common, for C and C++ programmers to use this sort of inappropriate global modelling. It's something which cannot scale, it works OK for one man projects, "Oh, I use the Special Goose Mode to make routine A better, so even though normal Elephants can't Teleport I need to remember that in Special Goose Mode the Elephants in routine B might Teleport". In practice you'll screw this up, but it feels like you'll get it right often enough to be valuable.
In a large project where we're doing software engineering this is complete nonsense, now Jenny, the newest member of the team working on routine A, will see that obviously Special Goose Mode is a great idea, and turn it on, whereupon the entirely different team handling routine B find that their fucking Elephants can now Teleport. WTF.
The need to never do this is why I was glad to see Rust stabilize (e.g) u32::unchecked_add fairly recently. This (unsafe obviously) method says no, I don't want checked arithmetic, or wrapping, or saturating, I want you to assume this cannot overflow. I am formally promising that this addition is never going to overflow, in order to squeeze out the last drops of performance.
Notice that's not a global flag. I can write let a = unsafe { b.unchecked_add(c) }; in just one place in a 50MLOC system, and for just that one place the compiler can go absolutely wild optimising for the promise that overflows never happen - and yet right next door, even on the next line, I can write let x = y + z; and that still gets the kid gloves, if it overflows nothing catches on fire. That's how granular this needs to be to be useful, unlike C++ -ffast-math.
Because the language works by textual inclusion and so a "translation unit" isn't really just your code this is much more likely to result in nasty surprises, up to and including ODR violations.
LLVM actually also supports instruction-level granularity for fast-math (using essentially the same mechanism as things like unchecked_add), but Clang doesn't expose that level of control.
Actually, floating-point math is mostly deterministic. There is an exception for rounding errors in transcendental functions.
The perception of nondeterminism came specifically from x87, which had 80-bit native floating-point registers, which were different from every other platform's 64-bit default, and forcing values to 64-bit all the time cost performance, so compilers secretly turned data types to different ones when compiling for x87, therefore giving different results. It would be like if the compiler for ARM secretly changed every use of 'float' into 'double'.
> This is perfectly appropriate in many settings, but _especially_ video games where such deterministic results are completely irrelevant.
I'm not sure I'd agree. Off the top of my head, a potentially significant benefit to deterministic floating-point is allowing you to send updates/inputs instead of world state in multiplayer games, which could be a substantial improvement in network traffic demand. It would also allow for smaller/simpler cross-machine/platform replays, though I don't know how much that feature is desired in comparison.
Indeed, but this isn't hypothetical. A large fraction of multiplayer games operate by sending inputs and requiring the simulation to be deterministic.
(Some of those are single-platform or lack cross-play support, and thus only need consistency between different machines running the same build. That makes compiler optimizations less of an issue. However, some do support cross-play, and thus need consistency between different builds – using different compilers – of the same source code.)
The existence of situations where the optimization is not appropriate, such as multiplayer input replay, does not invalidate the many situations where it is appropriate.
Sure, but I'm not sure anyone is trying to argue that -ffast-math is never appropriate. I was just trying to point out that your original claim that deterministic floating point is "completely irrelevant" to games was too strong.
Your comment boils down to 'all code should be perfect'. Which is a lovely request, but doesn't really help.
In particular, I'd challenge you to find one large program that handles OOM situations 100% correctly, especially since most code runs atop an OS configured to over-allocate memory. But even if it wasn't, I doubt there's any sizeable codebase that handles every memory allocation failure correctly and gracefully.
I don't think GP's statement was that all code everywhere must be perfect.
Just that code which is designed to be run in a separate process with the express intent of allowing termination at timeout should also be designed to not change state outside of itself. If somehow it really needs to (e.g. a 1TB working file), either that process or its invoker needs to have cleanup code that assumes processes have been terminated.
Doesn't mean that ALL code needs to be perfect, or even that this code will be, just that a thoughtful design will at least create the requirements and tests that make this model work.
Not perfect, but “crash-only” or at least as robust as such. Probably involving transactions of some sort. It is indeed a tall order, but if you’re sending kill signals to threads from the outside, that’s the reality you’re in. Find another abort mechanism if that’s too big an ask (and in most cases it justifiably is, that's why Java doesn't even allow it anymore)
You can never be perfect enough where you won’t drop crumbs on your keyboard but if you make a rule to never eat near your computer, you will never drop crumbs on your keyboard.
Writing high quality code is not about being perfect — it’s about changing how you write code.
Writing code that can recover from unexpected errors at any point is simply by being mindful about ordering your instructions and persisting data precisely.
> Your comment boils down to 'all code should be perfect'.
This is clearly false from a cursory skim of the parent comment, which says
> All processes should be prepared for a sudden crash without corrupting state.
...which is leagues away from "all code should be perfect" - for instance, an obvious example is programs that can crash at any time without state corruption, but contain logic bugs that result in invalid data being (correctly) written to disk, independent of crashing or being killed.
The convo has been a bit light on examples - I think a canonical example of how to achieve this can be found in ACID databases and high uptime mainframes. Definitely doable, but if performance and large scale data is also a concern, doing it from scratch (eg. starting with file handles) is probably a 5-10+ year process to write your own stable db.
I've not seen a very convincing use-case for ETags vs Last-Modified date caching.
In the example request, the server still has to do all of the work generating the page, in order to calculate the ETag and then determine whether or not the page has changed. In most situations, it's simpler to have timestamps to compare against, because that gives the server a faster way to spot unmodified data.
e.g. you get a HTTP request for some data that you know is sourced from a particular file, or a DB table. If the client sends a If-Modified-Since (or whatever the header name is), you have a good chance to be able to check the modified time of the data source before doing any complicated data processing, and are able to send back a not modified response sooner.
When I use ETags, I'll generate the ETag value once (on startup), then cache and serve that value. When the resource changes, regenerate the ETag value.
Obviously doesn't work if you're using ETags on dynamic resources, but works well for non-dynamic, but unpredictably frequently changing resources.
The whole point of the interview process is to assess not just the applicant's past achievements, but what they might be able to achieve if they got their place at the uni. Part of that is looking at the applicant's background, and knowing that even if they aren't currently at some elite high-fee school, they might still have the ability and capability to do well.
I am all in favor of this style of selection. The dark old days of "this kid's dad went to our college, we should do them a favour and let them in" are long gone, thankfully.
Can you point to any kind of evidence that Oxbridge are dumbing down their teaching, or lowering their standards of teaching? I doubt it.
Full disclosure: cambridge alumni, from a state school!